Zum Inhalt springen

AA_OUTBOX_EVENT

Status: Entwurf · Spec-Kandidat: ja

Zweck

Transactional-Outbox-Tabelle. Jeder Service-Aufruf, der Daten ändert, schreibt in derselben Transaktion einen AA_OUTBOX_EVENT. Ein separater Worker liest pending-Einträge und stellt sie an Konsumenten zu (Webhooks, Queue, externe Suchengine).

Damit gilt:

  • Atomicity: Kein Event ohne committed DB-Zustand, kein DB-Zustand ohne Event.
  • At-least-once: Worker quittiert nach erfolgreicher Zustellung; bei Crash wird wiederholt. Exactly-once ist nicht das Ziel.
  • Reihenfolge je Aggregat: Worker stellt Events mit gleicher aggregate_id strikt in id-Reihenfolge zu.
  • Idempotenz: Konsumenten verwenden id als Event-Key und müssen Doppel-Zustellung deduplizieren (persistenter Dedup-Speicher oder idempotente Handler).

Felder

FeldTypPflichtHinweise
idbigserialjaPK, monoton steigend → Reihenfolge-Anker
tenant_iduuidneinNULL für plattformweite Events
event_typetextjastabiler Name, Konvention <objekt>.<typ?>.<verb> (z. B. entity.customer.updated)
schema_versionintegerjadefault 1, für breaking-changes der Payload
aggregate_typetextjalogische Tabelle (z. B. DDM_ENTITY, DDM_ENTITY_RELATION, AA_ROLE)
aggregate_iduuidneinID des betroffenen Datensatzes (NULL für aggregat-lose Events)
audit_log_idbigintneinFK → AA_AUDIT_LOG — Verbindung zur fachlichen Audit-Zeile
correlation_iduuidneingruppiert mehrere Events einer Service-Operation
payloadjsonbjaversionsabhängige Eventdaten, JSON-Objekt-Constraint
statusmdm.outbox_statusjapending / dispatched / failed / skipped
attemptsintegerjadefault 0, ≥ 0
last_errortextneinletzte Fehlermeldung des Workers
available_attimestamptzjadefault now(); Worker rückt failed-Events mit Backoff in die Zukunft
dispatched_attimestamptzneinZeitpunkt der erfolgreichen Zustellung
created_at / created_bybei INSERT gesetzt

Constraints

  • outbox_event_payload_is_object_chk
  • outbox_event_attempts_chk (attempts >= 0)

Trigger

  • Keine. Tabelle ist append-only durch Service. Status-Updates nur durch den Worker.

Indizes

  • ix_outbox_event_pending partial auf (status, available_at, id) WHERE status='pending' — Worker-Hot-Path.
  • ix_outbox_event_aggregate auf (aggregate_type, aggregate_id, id) — Reihenfolge-Lookup je Aggregat.
  • ix_outbox_event_correlation partial auf correlation_id.

Verhalten

  • Erzeugung: Service schreibt AA_OUTBOX_EVENT in derselben Transaktion wie die fachliche Mutation. audit_log_id und correlation_id werden mitgegeben, damit ein Konsument den Audit-Kontext rekonstruieren kann.
  • Zustellung: Worker liest pending-Events in batch, sortiert per (aggregate_id, id), ruft Konsumenten auf, setzt bei Erfolg status='dispatched' und dispatched_at. Bei Fehler attempts++, last_error, exponential-backoff über available_at.
  • Retention (OP-22, gesetzt 2026-04-29): Erfolgreich zugestellte Events (status='dispatched') werden 10 Tage nach dispatched_at per AA_JOB.job_kind='outbox_compact' hart gelöscht. failed/skipped Events bleiben bis manuell quittiert. AA_AUDIT_LOG bleibt die langfristige Wahrheit (Retention 10 Jahre, OP-06).
  • Webhooks und Queues sind Konsumenten der Outbox, keine eigenständigen Schreibpfade.

Beispiel-Payload

{
"tenant_key": "public",
"entity_type": "customer",
"entity_id": "9c2…",
"code": "C-1001",
"version": 5,
"before": { "status": "draft" },
"after": { "status": "active" },
"actor": { "principal_type": "user", "principal_id": "1f3…" }
}

Verwandte Dokumente