fix(activity): a run nothing here has open reads as interrupted, a rollback sums a stopped run's spend

- The scheduler keeps one registry of the runs this process has open, for the interval jobs and the
  ad-hoc runs alike. A row the table still says is `running` but no run here has open (its outcome
  failed to write) reads as interrupted, as the next start's sweep will close it: no pulsing dot
  beside "No run recorded yet".
- Migration 0109's downgrade sums a still-running run's quota events into its spend before the link
  to them is dropped, as the startup sweep would.
- A test holds that a dialog closing onto the same address leaves an open log line open.
This commit is contained in:
2026-10-18 21:21:19 +02:00
parent 13b7577d9f
commit 5082636f15
5 changed files with 109 additions and 21 deletions
+11
View File
@@ -131,6 +131,13 @@ def test_a_down_and_up_round_trip_keeps_every_run(db, make_user):
),
{"u": uid},
)
# What the run caught mid-way had spent: only its quota rows know it yet.
conn.execute(
text(
"INSERT INTO quota_events (action, units, job_run_id)"
" SELECT 'videos.list', 7, id FROM job_runs WHERE job = 'maintenance'"
)
)
cfg = Config("alembic.ini")
command.downgrade(cfg, "0108_folder_links")
command.upgrade(cfg, "head")
@@ -141,6 +148,9 @@ def test_a_down_and_up_round_trip_keeps_every_run(db, make_user):
kept = conn.execute(
text("SELECT quota_units, finished_at - started_at FROM job_runs WHERE job = 'enrich'")
).one()
stopped = conn.execute(
text("SELECT quota_units FROM job_runs WHERE job = 'maintenance'")
).scalar()
stranded = conn.execute(
text("SELECT count(*) FROM audit_log WHERE action = 'job_run'")
).scalar()
@@ -151,4 +161,5 @@ def test_a_down_and_up_round_trip_keeps_every_run(db, make_user):
("enrich", "manual", None, None, "ok"),
]
assert tuple(kept) == (42, timedelta(minutes=30))
assert stopped == 7
assert stranded == 0
+26 -1
View File
@@ -460,13 +460,38 @@ def test_a_run_whose_outcome_cannot_be_written_is_not_called_failed(db, make_use
assert not scheduler._is_running("autotag")
(run,) = _runs(db, "autotag")
assert run.status == "running" # left for the next start's sweep, not rewritten as a failure
# Nothing here runs it: the page reads it as the sweep will close it, not as a run going on.
row = _row(db, "autotag")
assert (row["running"], row["status"], row["recent"][0]["status"]) == (
False,
"interrupted",
"interrupted",
)
assert row["last_finished"] is not None
user = make_user("blip@example.com")
calls.clear()
scheduler._ad_hoc("channel_backfill", lambda: {"videos_added": 1}, user.id, "UC_blip")
assert calls == ["ok"]
# Its row is still `running`, but nothing here is: the page does not call it going.
assert scheduler.scheduler_snapshot(db)["ad_hoc"][0]["running"] is False
(row,) = scheduler.scheduler_snapshot(db)["ad_hoc"]
assert (row["running"], row["status"], row["recent"][0]["status"]) == (
False,
"interrupted",
"interrupted",
)
def test_a_run_going_on_reads_as_running_on_its_row(db):
seen = []
scheduler._job("autotag", lambda _db: seen.append(_row(db, "autotag")) or {"tagged": 1})
(row,) = seen
assert (row["running"], row["status"], row["recent"][0]["status"]) == (True, None, "running")
assert _row(db, "autotag")["recent"][0]["status"] == "ok"
def _row(db, job_id: str) -> dict:
return next(j for j in scheduler.scheduler_snapshot(db)["jobs"] if j["id"] == job_id)
def test_a_run_that_cannot_be_recorded_does_not_wedge_its_job(db, monkeypatch):