CodamAIDocs
Themafertig

Ein Hook schreibt selbst

Legt ein Hook über einen System-Layer selbst etwas an, ist das ein Schreibvorgang im Schreibvorgang. Jeder bekommt seine eigene Ebene: eigene Prüfung, eigene Hooks, ein gemeinsamer Commit. Die Tiefe ist begrenzt und messbar.

Ausprägungen
Hook legt einen gültigen Datensatz anäußerer Datensatz ist ungültiginnerer Datensatz ist ungültigAfter-Hooks beider Ebeneninnerer Create mit LENIENTHook schreibt bei jedem Schreiben (zu tief)Maximaltiefe einstellenTiefe im Monitoring

Worum es geht

Ein Hook darf mehr als Felder setzen. Er kann über den System-Layer eines Modells selbst schreiben: einen Protokolleintrag anlegen, einen abgeleiteten Datensatz erzeugen, ein anderes Objekt ändern. Das ist ein zweiter Schreibvorgang, der mitten im ersten läuft.

CDMS behandelt jeden Schreibvorgang als eigene Ebene. Der Schreibvorgang des Requests ist Ebene 1, ein Schreibvorgang aus einem seiner Hooks Ebene 2 und so weiter.

Zwei Ebenen im Ablauf

Beispiel: Ein Before-Hook an Order legt zu jeder neuen Bestellung einen Protokolleintrag an.

sequenceDiagram
    participant C as Client
    participant S1 as System-Layer Order (Ebene 1)
    participant H as Before-Hook
    participant S2 as System-Layer Log (Ebene 2)
    participant DB as Datenbank
    C->>S1: POST /order/create
    S1->>S1: Graph bauen, Regeln sammeln
    S1->>H: Before-Hooks
    H->>S2: createObject(Log)
    S2->>S2: eigene Regeln, eigene Before-Hooks, eigene Meldung
    S2->>DB: Log schreiben (ohne Commit)
    S2->>S2: eigene After-Hooks
    S2-->>H: Log
    H-->>S1: fertig
    S1->>S1: eigene Regeln melden (422, falls verletzt)
    S1->>DB: Order schreiben
    S1->>S1: eigene After-Hooks
    S1-->>C: 200
    Note over S1,DB: Commit am Ende des Requests, für beide

Was dabei für jede Ebene gilt:

Ebene 1 (Order)Ebene 2 (Log)
Regelverstößenur die eigenen, gemeldet vor dem Schreiben von Ordernur die eigenen, gemeldet vor dem Schreiben von Log
Before-Hooksdie von Order und ihren Kinderndie von Log und seinen Kindern
After-Hookslaufen, nachdem Order geschrieben istlaufen, nachdem Log geschrieben ist
RechteKlassenrolle von Order, Feldrechte des AbstiegsKlassenrolle von Log; ein Feldrecht aus Ebene 1 gilt hier nicht
Commitam Ende des Requestskeiner, gehört zu Ebene 1

Was am Ende gespeichert ist

Hook legt einen Protokolleintrag an: was steht danach in der Datenbank?
BestellungProtokolleintragErgebnis
gültiggültig200, beide gespeichert
verletzt eine Regelgültig422 mit den Verstößen der Bestellung, nichts gespeichert
gültigverletzt eine Regel422 mit den Verstößen des Protokolleintrags, nichts gespeichert
egalHook wirftAntwort nach der Exception, siehe Wenn ein Hook scheitert, nichts gespeichert

Auch ein innerer Create, der createReadMode: LENIENT verlangt, committet nicht. LENIENT gilt nur für den Schreibvorgang des Requests, siehe Anlegen und Zurücklesen: STRICT oder LENIENT. Sonst wäre der Protokolleintrag schon festgeschrieben, bevor die Bestellung geprüft ist.

Wie tief es gehen darf

Ein Hook, der auf jedes Schreiben seines eigenen Modells wieder schreibt, würde nie aufhören. CDMS begrenzt deshalb die Tiefe:

Hook an Order legt bei jedem Schreiben eine neue Order an
  1. 1
    Client→CDMS
    POST /api/rest/order/create
  2. 2
    CDMS
    Ebene 1: Order, Before-Hook legt Order an
  3. 3
    CDMS
    Ebene 2, 3, … bis zur Maximaltiefe: jede Order legt die nächste an
  4. 4
    CDMS
    Die nächste Ebene läge über der Maximaltiefe
  5. 5
    CDMS
    HookExecutionException write-nesting-too-deep|10 → 500
  6. 6
    CDMS→Database
    ganzer Request wird zurückgerollt, keine einzige Order bleibt

Die Maximaltiefe stellst du in der application.yaml ein:

codamai:
  cdms:
    api:
      max-write-nesting-depth: 10   # Ebene 1 ist der Schreibvorgang des Requests

Die Antwort ist 500, nicht 4xx: Der Client hat nichts falsch gemacht, die Ursache ist ein Hook.

Im Monitoring

Hat die Anwendung Micrometer und eine Registry, misst CDMS jeden Schreibvorgang des Requests:

MetrikArtBedeutung
cdms.write.nesting.depthVerteilungdie tiefste Ebene, die ein Schreibvorgang erreicht hat; 1 heißt: kein Hook hat geschrieben
cdms.write.nesting.refusedZählerSchreibvorgänge, die wegen zu großer Tiefe abgelehnt wurden

Beide tragen das Modell des Schreibvorgangs auf Ebene 1 als Tag model. Ein Maximum, das langsam steigt, heißt: Hooks rufen Hooks auf. Jede Ablehnung steht zusätzlich als Warnung im Log.

Fallen

Wie es weitergeht

Quellen im Code und in der Wissensdatenbank
  • CDMS/cdms-system-layer – session/WriteNestingContext (enter, leave, isNested), ValidationRequestContext, FieldAccessContext, HookRequestContext (suspend, resume)
  • CDMS/cdms-system-layer – AbstractLayer (enterWrite, leaveWrite), AbstractSystemLayer, AbstractSystemSingletonLayer (createObject, updateObject, patchObject, deleteObject, historyRollback)
  • CDMS/cdms-system-layer – configurations/SystemSettings (maxWriteNestingDepth), observability/MicrometerWriteNestingObservability
  • CDMS/cdms-system-layer – docs/adr/adr-016-verschachtelte-schreibvorgaenge-haben-eigene-ebenen.md
  • CDMS/cdms-integrationtest – AbstractNestedWriteTest, NestedWriteSingleDbTest, NestedWriteMultiDbTest
  • documentation/60-erweiterung/01-hooks.md
Suchen