Hintergrundagenten: Nach einem Neustart nicht alles wiederholen

Ein Hintergrundlauf kann einen externen Vorgang auslösen und anschließend vor dem Speichern seines Abschlusses abbrechen.

Das Problem: Unklarer Abschluss

Ein Agent kann eine externe Aktion abgeschlossen haben, bevor der Server ausfällt. Nach dem Neustart könnte blindes Wiederholen diese Aktion duplizieren. Auch eine fehlgeschlagene Ergebniszustellung ist kein Grund, die eigentliche Modellarbeit erneut zu starten.

Die Lösung: Zustände dauerhaft speichern

Geplante Weckvorgänge werden dauerhaft gespeichert. Eine bedingte Datenbankübernahme verhindert die erneute Übernahme desselben wartenden Laufs. Ein beim Neustart laufender Vorgang wird als unterbrochen markiert, statt mögliche externe Wirkungen automatisch zu wiederholen.

Ausführung und Nachricht trennen

Ergebnisse werden getrennt von der Inbox-Zustellung gespeichert. Eine Outbox erlaubt neue Zustellungsversuche, ohne das Modell erneut auszuführen oder die Erinnerung zu duplizieren. Wartende Aufgaben lassen sich abbrechen; bereits laufende Arbeit konnte über diesen Knopf im dokumentierten Stand noch nicht abgebrochen werden.

Grenzen offen benennen

Der Worker arbeitet auf einem einzelnen Server und teilt die Ausführungssperre mit dem Chat. Ein laufender Hintergrundturn kann daher einen neuen Chat verzögern. Ein gespeichertes Resultat belegt weder das Erreichen eines größeren Ziels noch die Zustellung einer Benachrichtigung. Die Architektur behandelt diese Zustände getrennt. Die Quelle dokumentiert die Umsetzung, keine neue Ende-zu-Ende-Prüfung durch die Redaktion.

Arbeit und Ergebniszustellung haben eigene Zustände

Der schwierigste Moment liegt zwischen Wirkung und Bestätigung

Ein Hintergrundlauf kann einen externen Vorgang auslösen und anschließend vor dem Speichern seines Abschlusses abbrechen. Nach dem Neustart weiß die Anwendung dann nicht sicher, ob die Wirkung schon eingetreten ist. Ein automatischer Neustart derselben Arbeit könnte eine Nachricht doppelt senden oder eine Änderung wiederholen. Deshalb werden beim Start vorgefundene laufende Aufgaben als interrupted markiert. Dieser Zustand ist keine gewöhnliche Warteschlange. Er hält die Unsicherheit sichtbar und verhindert, dass aus einer technischen Wiederherstellung automatisch eine fachliche Wiederholung wird.

Die Übernahme braucht eine Bedingung in der Datenbank

Ein Worker wählt eine fällige Aufgabe aus und versucht, ihren Zustand von pending auf running zu ändern. Die Bedingung muss Teil der UPDATE-Operation sein. Erst wenn genau ein Datensatz übernommen wurde, darf der Lauf beginnen. Ein vorheriges SELECT mit anschließendem bedingungslosem UPDATE würde ein Rennen zwischen zwei Beteiligten zulassen. Das Codefenster zeigt die Kernoperation als SQL-Muster. Die reale Umsetzung verwendet den Datenbankzugriff des Projekts. Auch bei einem einzelnen Server ist diese Bedingung nützlich, weil Chat, Worker und Wiederaufnahme unterschiedliche Zeitpunkte haben.

-- Vereinfachte bedingte Übernahme einer fälligen Aufgabe.
UPDATE agent_wake
SET state = 'running', started_at = :now
WHERE id = :task_id
  AND state = 'pending'
  AND due_at <= :now;

-- Nur rowcount == 1 berechtigt zur Ausführung.
-- Wiederherstellung beim Neustart:
UPDATE agent_wake
SET state = 'interrupted'
WHERE state = 'running';

-- Ergebnis speichern und Zustellung separat vormerken.
-- Ein Zustellungs-Retry darf keinen neuen Modellturn starten.

Das Ergebnis wird vor dem Zustellungsversuch gespeichert

Ist die Arbeit abgeschlossen, wird ihr Resultat dauerhaft festgehalten. Die Inbox-Benachrichtigung erhält einen eigenen Zustellungszustand. Ein vorübergehender Zustellungsfehler wiederholt dadurch nur diesen Schritt, nicht den Modellturn. Das ist der Unterschied zwischen einem fehlenden Ergebnis und einem vorhandenen Ergebnis mit fehlender Nachricht. Die Task-Liste des Agenten liefert zudem Metadaten statt ungeprüfter Ergebnisprosa. Ein generierter Satz aus einer erledigten Aufgabe soll nicht über den Erinnerungsweg später als vertrauenswürdige Systemanweisung zurückkehren.

Technische Referenz: SQLite: Bedingte UPDATE-Operationen.

Betriebsgrenzen gehören zur Architektur

Der dokumentierte Worker begrenzt aktive Einträge, tägliche Starts, Folgeaufgaben und Laufzeit. Er teilt die Turnsperre mit dem Chat. Damit kann eine laufende Hintergrundarbeit einen neuen Chat verzögern; sie arbeitet nicht parallel auf beliebig vielen Servern. Wartende Aufgaben lassen sich abbrechen, eine bereits laufende Aktion wird dadurch nicht rückwirkend aufgehoben. Für die Abnahme prüfen wir daher vier Fälle getrennt: Neustart vor Übernahme, Neustart während des Laufs, gespeichertes Ergebnis mit ausgefallener Zustellung und Abbruch einer wartenden Aufgabe. Kein einzelner grüner Status deckt diese vier Übergänge ab.

Weiterlesen: Android-Erinnerungen: Zustellung muss sichtbar prüfbar sein.