Add scheduled watchlist refresh support
This commit is contained in:
@@ -335,6 +335,81 @@ class WatchlistRefreshJobs:
|
||||
self.current_job_id = None
|
||||
|
||||
|
||||
class WatchlistAutoRefreshScheduler:
|
||||
def __init__(self, config_getter, refresh_start_fn, start_worker=True):
|
||||
self.config_getter = config_getter
|
||||
self.refresh_start_fn = refresh_start_fn
|
||||
self.lock = threading.RLock()
|
||||
self.wakeup = threading.Event()
|
||||
self.stop_event = threading.Event()
|
||||
self.worker = None
|
||||
self.last_enabled = None
|
||||
self.last_interval_seconds = None
|
||||
self.last_attempt_monotonic = None
|
||||
if start_worker:
|
||||
self.ensure_worker()
|
||||
|
||||
def ensure_worker(self):
|
||||
with self.lock:
|
||||
if self.worker is not None and self.worker.is_alive():
|
||||
return
|
||||
self.stop_event.clear()
|
||||
self.worker = threading.Thread(target=self._run, daemon=True)
|
||||
self.worker.start()
|
||||
|
||||
def shutdown(self, wait=False):
|
||||
self.stop_event.set()
|
||||
self.wakeup.set()
|
||||
worker = self.worker
|
||||
if wait and worker is not None and worker.is_alive():
|
||||
worker.join(timeout=WORKER_SHUTDOWN_TIMEOUT_SECONDS)
|
||||
return worker is None or not worker.is_alive()
|
||||
|
||||
def notify_config_changed(self):
|
||||
self.wakeup.set()
|
||||
|
||||
def _config_state(self):
|
||||
config = self.config_getter() or {}
|
||||
enabled = bool(config.get("watchlist_auto_refresh_enabled"))
|
||||
try:
|
||||
minutes = int(str(config.get("watchlist_auto_refresh_minutes", 60)).strip() or "60")
|
||||
except (TypeError, ValueError):
|
||||
minutes = 60
|
||||
minutes = max(1, min(7 * 24 * 60, minutes))
|
||||
return enabled, minutes * 60
|
||||
|
||||
def tick(self, now_monotonic=None):
|
||||
now = time.monotonic() if now_monotonic is None else float(now_monotonic)
|
||||
enabled, interval_seconds = self._config_state()
|
||||
with self.lock:
|
||||
changed = enabled != self.last_enabled or interval_seconds != self.last_interval_seconds
|
||||
if changed:
|
||||
self.last_enabled = enabled
|
||||
self.last_interval_seconds = interval_seconds
|
||||
self.last_attempt_monotonic = now
|
||||
if not enabled:
|
||||
return None
|
||||
if self.last_attempt_monotonic is None:
|
||||
self.last_attempt_monotonic = now
|
||||
return interval_seconds
|
||||
remaining = interval_seconds - (now - self.last_attempt_monotonic)
|
||||
if remaining > 0:
|
||||
return remaining
|
||||
self.last_attempt_monotonic = now
|
||||
try:
|
||||
result = self.refresh_start_fn()
|
||||
debug_log("watchlist.auto_refresh.tick", result=result)
|
||||
except Exception as exc:
|
||||
debug_log("watchlist.auto_refresh.error", error=exc)
|
||||
return interval_seconds
|
||||
|
||||
def _run(self):
|
||||
while not self.stop_event.is_set():
|
||||
wait_seconds = self.tick()
|
||||
self.wakeup.wait(timeout=wait_seconds)
|
||||
self.wakeup.clear()
|
||||
|
||||
|
||||
class DownloadQueue:
|
||||
def __init__(self, config_getter, watchlist_sync_fn=None, job_prepare_fn=None, start_worker=True):
|
||||
self.config_getter = config_getter
|
||||
|
||||
Reference in New Issue
Block a user