fix: bound durable background job retention

This commit is contained in:
mARTin-B78 2026-09-04 09:24:14 +02:00
parent e234a6e9a3
commit c79a2efaab
4 changed files with 24 additions and 1 deletions

View File

@ -40,6 +40,8 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
- **Durable Background Job Metadata.** Transcription, voice design, casting, and consistent-image jobs now persist
bounded status metadata in SQLite; unfinished jobs are reported as interrupted after a server restart, while prompts,
secrets, audio, and image payloads are excluded from persistence.
- **Bounded Durable Job Retention.** Completed background-job metadata is pruned oldest-first at a fixed limit so
restart-safe status tracking cannot become an unbounded database growth path.
- **STT Cancellation Safety.** Queued transcription cancels before consuming the single STT slot, and timed-out
requests keep the device slot held until the underlying worker actually exits.
- **Credential Boundary Review.** Provider credentials are now documented as server-only; only the explicitly

View File

@ -1 +1 @@
1.22.9
1.23.0

View File

@ -254,6 +254,11 @@ def background_job_create(job_id: str, kind: str, *, fingerprint: str = "", crea
"VALUES (?,?,?,?,?,?,?,?,?,?,?)",
(str(job_id), str(kind)[:80], "queued", "Queued", 0, 0, None, None, str(fingerprint)[:128], now, now),
)
conn.execute(
"DELETE FROM background_jobs WHERE job_id IN ("
"SELECT job_id FROM background_jobs WHERE done=1 ORDER BY updated ASC "
"LIMIT -1 OFFSET 255)"
)
conn.commit()

View File

@ -194,6 +194,22 @@ class SecurityValidationTests(unittest.TestCase):
conn.execute("DELETE FROM background_jobs WHERE job_id=?", (job_id,))
conn.commit()
def test_background_job_persistence_prunes_old_completed_rows(self):
from core.database import _open, background_job_create, background_job_update
prefix = "prune-job-"
try:
for index in range(260):
job_id = prefix + str(index)
background_job_create(job_id, "test")
background_job_update(job_id, stage="done", done=True)
with _open() as conn:
count = conn.execute("SELECT COUNT(*) FROM background_jobs WHERE job_id LIKE ?", (prefix + "%",)).fetchone()[0]
self.assertLessEqual(count, 256)
finally:
with _open() as conn:
conn.execute("DELETE FROM background_jobs WHERE job_id LIKE ?", (prefix + "%",))
conn.commit()
def test_fish_cache_eviction_is_bounded(self):
from pathlib import Path
from tempfile import TemporaryDirectory