58 lines
1.5 KiB
Python
58 lines
1.5 KiB
Python
from datetime import datetime
|
|
|
|
from pydantic import BaseModel
|
|
|
|
|
|
class HealthResponse(BaseModel):
|
|
status: str
|
|
queue_counts: dict[str, int]
|
|
worker_count: int
|
|
poller_count: int
|
|
# Live counters — non-zero shortfalls vs the configured count signal a
|
|
# crashed task. status="degraded" when either shortfall is non-zero so
|
|
# uptime monitors can alert without needing to do the math themselves.
|
|
workers_alive: int
|
|
pollers_alive: int
|
|
|
|
|
|
class SourceSummary(BaseModel):
|
|
source_id: str
|
|
type: str
|
|
last_polled_at: datetime | None
|
|
circuit_breaker_open: bool
|
|
# Reason the most recent sweep attempt was skipped (e.g. "pending_work"),
|
|
# or None when the most recent attempt actually polled. Lets operators
|
|
# see at a glance why a source isn't picking up new work.
|
|
last_skip_reason: str | None = None
|
|
|
|
|
|
class RefreshResponse(BaseModel):
|
|
source_id: str
|
|
refreshed: bool
|
|
|
|
|
|
class CancelResponse(BaseModel):
|
|
job_id: str
|
|
cancelled: bool
|
|
|
|
|
|
class ThroughputStats(BaseModel):
|
|
succeeded_5m: int
|
|
succeeded_30m: int
|
|
succeeded_1h: int
|
|
|
|
|
|
class WorkerStats(BaseModel):
|
|
busy: int
|
|
total: int
|
|
|
|
|
|
class StatsResponse(BaseModel):
|
|
"""Aggregated counters and per-source breakdowns that drive the dashboard.
|
|
Cheap to compute (all SQL aggregations against the queue file)."""
|
|
|
|
throughput: ThroughputStats
|
|
workers: WorkerStats
|
|
oldest_queued_age_s: float | None
|
|
dlq_by_source: dict[str, int]
|
|
queue_depth_by_source: dict[str, int]
|