Files
nexarch/dms/docs/FDN-04-PRUEFPROTOKOLL.md
T
sysopsandClaude Sonnet 5 bfea94b032 FDN-04: job-queue & worker-runtime
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
2026-08-29 20:58:26 +02:00

4.4 KiB
Raw Blame History

FDN-04 Prüfprotokoll: Job-Queue & Worker-Runtime

Welle 3. Voraussetzung: FDN-02 (Status "Fertig").

Umsetzung

internal/jobqueue:

  • migrations/tenant/0002_processing_jobs.up.sqlprocessing_jobs-Tabelle (Status pending/processing/succeeded/failed/dead_letter, attempts/max_attempts, available_at für Backoff-Terminierung, locked_at/locked_by für die Sperre, idempotency_key UNIQUE).
  • Queue.Enqueue — reiht ein, mit optionalem idempotency_key (Dedup bei Doppelzustellung, ON CONFLICT DO UPDATE ... RETURNING id).
  • Queue.DequeueFOR UPDATE SKIP LOCKED, holt entweder einen fälligen pending-Job oder einen processing-Job, dessen Sperre älter als staleLockAfter ist (Absturz-Wiedervorlage). Backoff-Intervallarithmetik über LEAST(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 in dead_letter.
  • Queue.RequeueDeadLetter — manuelle Wiederholung eines DLQ-Eintrags.
  • Queue.Status — Job-Status abfragbar.
  • Worker/Handler — In-Prozess-Worker-Goroutine, pollt und ruft Handler je Job auf.

Prüfungen

# Prüfung Ergebnis
1 Absturz eines Workers führt zu erneuter Zustellung bestandenTestDequeue_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 bestandenTestEnqueue_IdempotencyKeyPreventsDuplicate: zweifache Einreihung mit gleichem idempotency_key erzeugt nachweislich nur 1 Zeile (per Abfrage bestätigt)
3 DLQ-Eintrag manuell wiederholbar bestandenTestRequeueDeadLetter: 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)

  1. pgx-Typinferenz-Fehler bei ungenutztem Parameter: Dequeues SQL übergab workerID als $1, ohne es in der Query zu referenzieren — Postgres/pgx konnte den Typ von $1 dadurch nicht ableiten (SQLSTATE 42P18). Behoben durch Entfernen des toten Parameters (workerID wird erst im nachfolgenden UPDATE gebraucht).
  2. $2::text[]-Cast mit untypisiertem nil: typeFilter any (statt []string) ließ pgx den Zieltyp des Casts nicht auflösen. Behoben durch []string-Typisierung der Variable.
  3. Testinfrastruktur-Drift über Sitzungsgrenzen: dms_tenant_test sammelte über mehrere Testläufe (FDN-02/03/04) schema_migrations-Zustand an, wodurch internal/migrates Rollback-Test nur noch einen Teil der Tabellen zurückrollte. Neues scripts/reset-test-env.sh (Datenbank droppen+neu anlegen, analog Core scripts/reset-test-env.sh) sowie make check-Target (Reset+vet+lint+test in einem Rutsch) behoben das strukturell. Zusätzlich fehlte -p 1 im test-Target — mehrere Testpakete teilen sich dieselbe physische Test-DB, parallele Paketausführung (Go-Testdefault) verursachte Querschläger zwischen internal/jobqueue und internal/migrate.
  4. internal/jobqueues Test-Fixture räumte nicht auf: TRUNCATE statt DROP TABLE ließ die Tabelle processing_jobs stehen, wodurch internal/migrates eigene, versionierte Migration mit relation already exists scheiterte. Behoben durch DROP TABLE IF EXISTS im 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.