feat(worker): ручной пересчёт метрик через очередь, диагностика шагов и heartbeat

POST /metrics/refresh ставит задачу в sync_job (source=METRICS_JOB) и отвечает 202, пересчёт делает worker; GET /metrics/status отдаёт refreshing и consistent. metric_refresh_log хранит failed_step и step_timings. Источники с needs="tinvest_token" не попадают в расписание без токена, tinvest/moex добавлены в default_schedule. Воркер трогает heartbeat-файл для healthcheck.
This commit is contained in:
Dmitry
2026-09-19 21:54:30 +03:00
parent 989a780f9f
commit 3b3ee4d682
11 changed files with 341 additions and 30 deletions
@@ -72,6 +72,7 @@ from fintracker.models.reports import (
ReportParseStatus,
)
from fintracker.models.sync import (
METRICS_JOB,
JobStatus,
RunStatus,
SourceCredential,
@@ -101,6 +102,7 @@ from fintracker.models.zenmoney import (
__all__ = [
"EXTERNAL_FLOW_KINDS",
"METRICS_JOB",
"POSITION_KINDS",
"Account",
"AccountKind",
+5
View File
@@ -135,6 +135,11 @@ class MetricRefreshLog(Base):
trigger: Mapped[str] = mapped_column(String(32))
"""sync:<source> | manual | cli"""
error: Mapped[str | None] = mapped_column(Text)
failed_step: Mapped[str | None] = mapped_column(String(64))
"""Name of the step that raised. Steps before it committed and the ones after it did not
run, so the metric tables then come from two different runs."""
step_timings: Mapped[dict[str, Any] | None]
"""Seconds per step that completed, in run order."""
class MetricPortfolioValueDaily(Base):
+7 -1
View File
@@ -19,6 +19,11 @@ class RunStatus(enum.StrEnum):
error = "error"
METRICS_JOB = "metrics"
"""`sync_job.source` of a queued metrics rebuild. Not a registered source: the worker
routes it to `refresh_all` instead of `run_source`, and `POST /sync/{source}` answers 404."""
class JobStatus(enum.StrEnum):
queued = "queued"
running = "running"
@@ -55,7 +60,8 @@ class SyncRun(Base):
class SyncJob(Base):
"""Manual trigger queue: API inserts, worker picks up (plan §2.4)."""
"""Manual trigger queue: API inserts, worker picks up (plan §2.4). Also carries the metrics
rebuild requested by `POST /metrics/refresh`, as `source == METRICS_JOB`."""
__tablename__ = "sync_job"