coordinate jobs: daily pipeline orchestrator runs the flow in order
Deploy / lint (push) Successful in 7s
Deploy / test (push) Successful in 39s
Deploy / deploy (push) Successful in 25s

Jobs were independent 24h timers with no ordering, so the scanner could run on
stale OHLCV, and manual runs desynced the offsets. New daily_pipeline job runs
the data→signal flow in dependency order: OHLCV → fundamentals → sentiment →
R:R scan → outcome eval (+paper close) → market regime. Each step keeps its own
enable flag and runtime status; a failing step is logged and the pipeline
continues.

The member jobs are registered PAUSED (no auto-fire) so they only run via the
pipeline — but stay manually triggerable from Admin → Jobs (shown as "runs in
daily pipeline"). Alerts (hourly), ticker universe sync, and backtest keep their
own independent cadence.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-17 10:16:41 +02:00
parent fb3b8d18d7
commit e982487abd
5 changed files with 114 additions and 94 deletions
+13
View File
@@ -485,6 +485,7 @@ VALID_JOB_NAMES = {
"alerts",
"market_regime",
"backtest",
"daily_pipeline",
}
JOB_LABELS = {
@@ -497,6 +498,17 @@ JOB_LABELS = {
"alerts": "Alerts Dispatcher",
"market_regime": "Market Regime",
"backtest": "Backtest",
"daily_pipeline": "Daily Pipeline",
}
# Jobs driven by the daily_pipeline (in order) rather than their own timer.
PIPELINE_MEMBERS = {
"data_collector",
"fundamental_collector",
"sentiment_collector",
"rr_scanner",
"outcome_evaluator",
"market_regime",
}
@@ -527,6 +539,7 @@ async def list_jobs(db: AsyncSession) -> list[dict]:
"label": JOB_LABELS.get(name, name),
"enabled": enabled,
"next_run_at": next_run,
"via_pipeline": name in PIPELINE_MEMBERS,
"registered": job is not None,
"running": bool(runtime.get("running", False)),
"runtime_status": runtime.get("status"),