Status: Proposed
Date: 2026-04-22
Deciders: software-architect
Related: ADR 0013 (MBT paper-trading engine, §8), docs/architecture/founders-trial-engine.md §8
Parent card: #206
The Founders trial engine needs a daily job that scans all non-terminal founder_trial rows, fires warning transitions (30d / 14d / 7d / 1d), and advances expired rows through grace into lapsed. The job must be:
Two candidates: APScheduler (in-process, simple) or Celery beat (the scheduler that drives all MBT background jobs).
Use Celery beat.
The Founders daily sweep (founders.daily_sweep) is registered as a Celery beat periodic task on the existing Celery + Redis stack already chosen for MBT (ADR 0013 §8). It is not a new dependency; it is a new task on a running scheduler.
mbt.eod_mark_all, mbt.purge_expired, etc.). Adding founders.daily_sweep is a task registration, not a stack addition.FOUNDERS_PROMO_SCHEDULER_DISABLED=1 removes the task from the schedule without a code change.APScheduler runs inside the Flask/gunicorn process. It is simple to configure and has no external dependencies.
Rejected because: - In a multi-worker gunicorn setup (multiple processes), APScheduler fires from every worker process simultaneously — the sweep would run N times per minute per machine unless a distributed lock is added. Adding a Redis-based lock to make APScheduler safe is most of the complexity of Celery beat, with fewer benefits. - Failures are unobservable from the standard Celery/Flower monitoring surface. - If the web process crashes and restarts, APScheduler's in-memory state is lost. Celery beat persists its schedule state in the beat store. - APScheduler is not in the existing MBT stack. Adding it solely for Founders creates a second async job runtime to operate.
Rejected. Cron on the server is fragile (must be configured per deployment), not portable to container-based hosting, and not visible from the app's internal monitoring. GitHub Actions scheduled workflows have a ±30 min jitter and are not designed for operational DB sweeps.
Rejected for v1 per ADR 0013 rationale: adds a dedicated cluster, new mental model, and higher ops footprint. The Founders sweep is a simple daily scan — not a stateful long-running workflow. Temporal is the right answer if we later build multi-day saga orchestration; it is overkill here.