diff --git a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_webpage_generator.py b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_webpage_generator.py index 4a0abda..945856a 100644 --- a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_webpage_generator.py +++ b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_webpage_generator.py @@ -235,6 +235,16 @@ class HttpUploader: self._uploaded: dict[str, float] = {} # abs path -> mtime at last upload self._lock = threading.Lock() self._busy = False # True while an upload thread is running + self._warn_at: dict[str, float] = {} # key -> epoch of last warning + + _WARN_COOLDOWN_S = 60 # only repeat the same warning once per minute + + def _warn(self, key: str, msg: str) -> None: + """Log a warning at most once per _WARN_COOLDOWN_S for a given key.""" + now = _epoch() + if now - self._warn_at.get(key, 0) >= self._WARN_COOLDOWN_S: + self._warn_at[key] = now + logger.warning(msg) # ── Public API ────────────────────────────────────────────────────────── @@ -297,7 +307,7 @@ class HttpUploader: import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) except ImportError: - logger.warning("HttpUploader: 'requests' library not installed") + self._warn("no_requests", "HttpUploader: 'requests' library not installed") return for path in files: @@ -318,14 +328,16 @@ class HttpUploader: ) if r.status_code == 200: self._uploaded[str(path)] = mtime + self._warn_at.pop(f"upload_{path.name}", None) # clear on success logger.debug(f"HttpUploader: OK {path.name}") else: - logger.warning( + self._warn( + f"upload_{path.name}", f"HttpUploader: {path.name} -> HTTP {r.status_code}: " f"{r.text[:120]}" ) except Exception as exc: - logger.warning(f"HttpUploader: {path.name} failed: {exc}") + self._warn(f"upload_{path.name}", f"HttpUploader: {path.name} failed: {exc}") def _do_cleanup(self) -> None: try: @@ -342,13 +354,14 @@ class HttpUploader: verify=False, # accept self-signed / untrusted certs ) logger.info(f"HttpUploader cleanup: {r.text[:120]}") + self._warn_at.pop("cleanup", None) # clear on success # Forget mtime records for ptycho files so they get re-uploaded with self._lock: to_remove = [k for k in self._uploaded if "/S" in k or "\\S" in k] for k in to_remove: self._uploaded.pop(k, None) except Exception as exc: - logger.warning(f"HttpUploader cleanup failed: {exc}") + self._warn("cleanup", f"HttpUploader cleanup failed: {exc}") # ---------------------------------------------------------------------------