Add find_missing_ebooks scheduled job

Introduce a safety-net scheduled job that scans completed audiobooks and auto-triggers ebook fetches for missing companions. Changes include:

- New Prisma migration + schema field: requests.ebook_auto_retry_count (nullable) to track lifetime auto-retries.
- New processor: src/lib/processors/find-missing-ebooks.processor.ts implementing the scan (limit 50), gating by ebook_auto_grab_enabled and source flags, creating ebook child requests or retrying failed ones up to a cap of 5, using transactions for race-safety and rolling back the counter if enqueue fails.
- Job queue integration: add job type, payload, processor registration, and addFindMissingEbooksJob helper.
- Scheduler integration: register the scheduled job (daily midnight) and trigger path.
- Documentation updates: backend scheduler and ebook-sidecar docs describing behavior and limits.
- Tests: add comprehensive unit tests for the processor and update scheduler tests and job-queue test helper.

This implements automated recovery for missing ebook companions while keeping the retry counter processor-private and ensuring safe concurrency handling.
This commit is contained in:
kikootwo
2026-05-17 18:22:55 -04:00
parent 6ec53ff7e3
commit 06195e6570
10 changed files with 831 additions and 4 deletions
@@ -0,0 +1,5 @@
-- Add lifetime auto-retry counter for the find_missing_ebooks scheduled job.
-- Nullable: NULL distinguishes "never touched by this job" from 0.
-- Only the find-missing-ebooks processor reads/writes/increments this column.
-- Manual Fetch Ebook routes do not touch it (counter is sacred per engineering brief).
ALTER TABLE "requests" ADD COLUMN "ebook_auto_retry_count" INTEGER;
+1
View File
@@ -234,6 +234,7 @@ model Request {
downloadAttempts Int @default(0) @map("download_attempts")
importAttempts Int @default(0) @map("import_attempts")
maxImportRetries Int @default(5) @map("max_import_retries")
ebookAutoRetryCount Int? @map("ebook_auto_retry_count")
lastSearchAt DateTime? @map("last_search_at")
customSearchTerms String? @map("custom_search_terms") @db.Text
lastImportAt DateTime? @map("last_import_at")