"""notify-send, every 60 seconds: seed the rules, note a new build, run the watch checks (at most every 15 minutes) and deliver the events nobody has handled yet. Not pausable.""" from __future__ import annotations import time as clock from datetime import datetime from ...feed.config import FeedSettings from ...notify import seed as seed_rules from ...notify import send, watch from . import Counts, JobContext, JobSpec, directory, reload_departments EVERY_SECONDS = 60 WATCH_SECONDS = 15 * 60 WATCH_KEY = "notify.watch_at" BUILD_KEY = "notify.build_noted" def _due(ctx: JobContext, key: str, seconds: float) -> bool: """True once per `seconds` per worker process; marks the time when it says so.""" now = clock.monotonic() with ctx.stack.lock: last = ctx.stack.cache.get(key) if last is not None and now - float(last) < seconds: return False ctx.stack.cache[key] = now return True def run(ctx: JobContext) -> Counts: conn, s = ctx.conn, ctx.settings counts: Counts = {} added = seed_rules(conn, s) if added: counts["seeded"] = len(added) if _due(ctx, BUILD_KEY, float("inf")): try: if watch.note_build(conn, s.ps_build) is not None: counts["version_deployed"] = s.ps_build except Exception as e: ctx.stack.drop(BUILD_KEY) # try again on the next run ctx.error(f"version check: {type(e).__name__}", degrade=False) if _due(ctx, WATCH_KEY, WATCH_SECONDS): for name, check in (("drawings", watch.check_drawings), ("change orders", watch.check_change_orders)): try: counts.update(check(conn)) except Exception as e: ctx.log.exception("watch check %s failed", name) ctx.error(f"watch {name}: {type(e).__name__}") pending = conn.execute( "SELECT EXISTS (SELECT 1 FROM notification_events WHERE dispatched_at IS NULL AND event_type IS NOT NULL)" ).fetchone()[0] if pending: reload_departments(conn) out = send.dispatch_pending(conn, s, directory(ctx)) counts.update(out) if out.get("failed") or out.get("retry"): ctx.degrade(f"{out.get('failed', 0)} failed, {out.get('retry', 0)} waiting for the directory") return counts def _cadence(_: FeedSettings, __: datetime) -> int: return EVERY_SECONDS SPEC = JobSpec(name="notify-send", run=run, cadence=_cadence, pausable=False)