feat(I3): always-on pipeline status indicator in the top nav
New /api/system/activity/summary aggregates scheduler health + per-queue pending depths + running count + 24h failure count in one cached call (safe to poll app-wide). PipelineStatusChip lives in the TopNav on every page: a compact running/queued/failing chip with a scheduler-health dot that expands to a popover (scheduler, busy queues, counts, link to downloads). Polls the summary every 8s, paused when backgrounded. Reuses the queue-cache read via _queues_cached(). + API test for the summary shape. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -44,6 +44,25 @@ async def test_queues_returns_all_known_queues(client, monkeypatch):
|
||||
assert set(body["queues"].keys()) == set(activity_module._QUEUE_NAMES)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_summary_returns_rollup_shape(client, monkeypatch):
|
||||
def _fake():
|
||||
return {
|
||||
"queues": {**dict.fromkeys(activity_module._QUEUE_NAMES, 0), "ml": 3},
|
||||
"fetched_at": datetime.now(UTC).isoformat(),
|
||||
}
|
||||
monkeypatch.setattr(activity_module, "_read_queues_sync", _fake)
|
||||
|
||||
resp = await client.get("/api/system/activity/summary")
|
||||
assert resp.status_code == 200
|
||||
body = await resp.get_json()
|
||||
assert set(body.keys()) == {"scheduler", "queues", "queued_total", "running", "failing"}
|
||||
assert body["queued_total"] == 3 # only ml has a non-zero depth
|
||||
assert isinstance(body["running"], int)
|
||||
assert isinstance(body["failing"], int)
|
||||
assert set(body["scheduler"]) == {"last_tick_at", "next_due_at", "due_now", "auto_sources"}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_queues_cached_within_ttl(client, monkeypatch):
|
||||
call_count = {"n": 0}
|
||||
|
||||
Reference in New Issue
Block a user