Postgres-Jobqueue (processing_jobs, FOR UPDATE SKIP LOCKED), In-Prozess- Worker-Goroutinen, kein Redis/AMQP. Enqueue mit Idempotency-Key-Dedup, Dequeue mit Stale-Lock-Wiedervorlage (Absturzsicherheit), Fail mit arithmetischem Backoff und Dead-Letter-Queue nach erschoepften Versuchen, RequeueDeadLetter fuer manuelle Wiederholung. Auf 192.168.1.131 verifiziert: Absturz-Wiedervorlage (Job von einem "abgestuerzten" Worker nie completed/failed, zweiter Worker holt ihn nach Ablauf der Sperre erneut), Idempotenz bei Doppelzustellung (gleicher idempotency_key erzeugt nur 1 Zeile), DLQ-Eintrag manuell wiederholbar. Vier reale Fehler beim Testen gefunden und behoben: zwei pgx-Typinferenz- Bugs im SQL-Parameterhandling (toter workerID-Parameter ohne Referenz in der Query; untypisiertes any statt []string fuer den ::text[]-Cast), sowie zwei Testinfrastruktur-Bugs (dms_tenant_test sammelte schema_migrations- Zustand ueber Sitzungen hinweg an, jobqueue-Testfixture raeumte processing_jobs nicht auf) - neues scripts/reset-test-env.sh + make check (-p 1) analog Core behoben. Siehe dms/docs/FDN-04-PRUEFPROTOKOLL.md fuer alle Pruefungsergebnisse. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
4.4 KiB
4.4 KiB
FDN-04 – Prüfprotokoll: Job-Queue & Worker-Runtime
Welle 3. Voraussetzung: FDN-02 (Status "Fertig").
Umsetzung
internal/jobqueue:
migrations/tenant/0002_processing_jobs.up.sql—processing_jobs-Tabelle (Statuspending/processing/succeeded/failed/dead_letter,attempts/max_attempts,available_atfür Backoff-Terminierung,locked_at/locked_byfür die Sperre,idempotency_keyUNIQUE).Queue.Enqueue— reiht ein, mit optionalemidempotency_key(Dedup bei Doppelzustellung,ON CONFLICT DO UPDATE ... RETURNING id).Queue.Dequeue—FOR UPDATE SKIP LOCKED, holt entweder einen fälligenpending-Job oder einenprocessing-Job, dessen Sperre älter alsstaleLockAfterist (Absturz-Wiedervorlage). Backoff-Intervallarithmetik überLEAST(attempts, 10) * interval '30 seconds'— arithmetischer Cast, keine String-Konkatenation (siehe "Bekannte Fehler vermeiden").Queue.Complete/Queue.Fail— bei erschöpften Versuchen wandert der Job indead_letter.Queue.RequeueDeadLetter— manuelle Wiederholung eines DLQ-Eintrags.Queue.Status— Job-Status abfragbar.Worker/Handler— In-Prozess-Worker-Goroutine, pollt und ruftHandlerje Job auf.
Prüfungen
| # | Prüfung | Ergebnis |
|---|---|---|
| 1 | Absturz eines Workers führt zu erneuter Zustellung | bestanden — TestDequeue_StaleLockIsRedelivered: Job wird von worker-crashed gesperrt, NIE completed/failed (simulierter Absturz); sofortiger erneuter Dequeue-Versuch liefert ErrNoJobAvailable (Sperre noch frisch), nach Ablauf von staleLockAfter liefert worker-2 denselben Job |
| 2 | Idempotenz bei Doppelzustellung nachgewiesen | bestanden — TestEnqueue_IdempotencyKeyPreventsDuplicate: zweifache Einreihung mit gleichem idempotency_key erzeugt nachweislich nur 1 Zeile (per Abfrage bestätigt) |
| 3 | DLQ-Eintrag manuell wiederholbar | bestanden — TestRequeueDeadLetter: Job nach erschöpften Versuchen in dead_letter, RequeueDeadLetter setzt zurück auf pending mit attempts=0; Requeue eines NICHT-DLQ-Jobs wird korrekt abgewiesen |
Reale Fehler gefunden und behoben (kein Vorab-Wissen, beim Testen entdeckt)
- pgx-Typinferenz-Fehler bei ungenutztem Parameter:
Dequeues SQL übergabworkerIDals$1, ohne es in der Query zu referenzieren — Postgres/pgx konnte den Typ von$1dadurch nicht ableiten (SQLSTATE 42P18). Behoben durch Entfernen des toten Parameters (workerID wird erst im nachfolgendenUPDATEgebraucht). $2::text[]-Cast mit untypisiertemnil:typeFilter any(statt[]string) ließ pgx den Zieltyp des Casts nicht auflösen. Behoben durch[]string-Typisierung der Variable.- Testinfrastruktur-Drift über Sitzungsgrenzen:
dms_tenant_testsammelte über mehrere Testläufe (FDN-02/03/04)schema_migrations-Zustand an, wodurchinternal/migrates Rollback-Test nur noch einen Teil der Tabellen zurückrollte. Neuesscripts/reset-test-env.sh(Datenbank droppen+neu anlegen, analog Corescripts/reset-test-env.sh) sowiemake check-Target (Reset+vet+lint+test in einem Rutsch) behoben das strukturell. Zusätzlich fehlte-p 1imtest-Target — mehrere Testpakete teilen sich dieselbe physische Test-DB, parallele Paketausführung (Go-Testdefault) verursachte Querschläger zwischeninternal/jobqueueundinternal/migrate. internal/jobqueues Test-Fixture räumte nicht auf:TRUNCATEstattDROP TABLEließ die Tabelleprocessing_jobsstehen, wodurchinternal/migrates eigene, versionierte Migration mitrelation already existsscheiterte. Behoben durchDROP TABLE IF EXISTSim Test-Cleanup.
Build/Test-Ergebnis (192.168.1.131, make check)
go build ./... -> clean
scripts/reset-test-env.sh -> dms_tenant_test leer neu angelegt
go vet ./... -> clean
golangci-lint run ./... -> 0 issues
go test ./... -p 1 -count=1 -> 4/4 Pakete ok, 0 Fehlschläge (inkl. 8 jobqueue-Tests, 3 migrate-Tests, 6 storage-Tests real gegen MinIO)
Gesamtergebnis
Bestanden. Alle drei Akzeptanzkriterien und alle drei Pflichtprüfungen erfüllt. Vier reale Fehler beim Testen gefunden und behoben (zwei Produktionscode-Bugs im SQL-Parameterhandling, zwei Testinfrastruktur-Bugs) — bestätigt erneut den Wert, jede Prüfung tatsächlich auf einem echten Testhost auszuführen statt nur zu behaupten.