Nightbot-Befund #99/#16 (P1): recoverStale gab "running"-Jobs nach starren fünf Minuten wieder frei, ohne zu prüfen, ob der ursprüngliche Worker noch aktiv daran arbeitet. Ein legitim länger laufender Job (z. B. ein langsamer Connector-Abgleich) konnte dadurch von einem zweiten Worker parallel erneut gestartet werden – Doppelausführung, z. B. doppelte Provisionierung oder doppelter Mailversand. - Migration 032: jobs.lease_id (pro Übernahme neu vergeben) und jobs.locked_by (Worker-Kennung, nur Diagnose). - runOnce vergibt beim Übernehmen einen frischen Lease und hält locked_at per Heartbeat alle 60 s aktuell, solange der Handler läuft. Jedes Abschluss-UPDATE (Erfolg wie Fehler) ist an genau diesen Lease gebunden (WHERE lease_id = ?); hat recoverStale die Zeile inzwischen doch freigegeben, verpufft ein verspätetes Ergebnis wirkungslos statt den neuen Versuch zu überschreiben. - recoverStale reißt jetzt nur noch Jobs an sich, deren Heartbeat tatsächlich ausgeblieben ist (locked_at älter als 5 Minuten), nicht mehr solche, die einfach nur lange laufen. Löscht lease_id beim Freigeben mit. Verifiziert: (a) SQL-Ebene direkt durchexerziert – frischer Heartbeat verhindert das Anreißen, ausgebliebener Heartbeat löst es aus, ein verspätetes Abschluss-UPDATE mit altem Lease betrifft 0 Zeilen; (b) echter Code über runOnce/recoverStale gegen die Testdatenbank – Job durchläuft Übernahme, Fehlschlag, lease-gebundenes Abschluss-UPDATE korrekt. Worker neu gestartet, läuft fehlerfrei, 1437 bestehende Jobs weiterhin 'succeeded'. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
6 lines
564 B
SQL
6 lines
564 B
SQL
-- Nightbot-Befund #99/#16: recoverStale gab "running"-Jobs nach starren 5 Minuten wieder frei, ohne zu prüfen,
|
|
-- ob der ursprüngliche Worker noch aktiv daran arbeitet. Ein legitim länger laufender Job konnte dadurch von
|
|
-- einem zweiten Worker parallel erneut gestartet werden (Doppelausführung).
|
|
ALTER TABLE jobs
|
|
ADD COLUMN lease_id CHAR(36) NULL, -- pro Übernahme neu vergeben; nur der aktuelle Lease darf das Ergebnis schreiben
|
|
ADD COLUMN locked_by VARCHAR(100) NULL; -- Worker-Kennung (Host:PID:Zufall) für Diagnose, kein Sicherheitsmerkmal
|