← Developers

01.2 — CDC outbox e canale di sync

Spec riferita a SPEC-DX-01 / sync v1

L’Invariante

Una scrittura business committata non deve mai perdersi tra il commit locale e la consegna al cloud. Il kernel scrive riga business, riga di audit ed entry outbox nella stessa transazione — se la riga esiste, l’evento raggiungerà il cloud. Il canale di sync è asincrono per design: prima l’autonomia edge, la convergenza cloud arriva dopo.

Il Contratto

interface OutboxEntry {          // ax_cdc_outbox (lato edge)
  id: string;                    // uuid — diventa la chiave di dedup globale
  aggregate_type: string;        // BIZ_*
  aggregate_id: string;
  event_type: string;            // INSERT_* | UPDATE_*
  payload: object;
  created_at: string;            // UTC
}
// Lato cloud: cp_events lo conserva verbatim; cp_event_dedup(id) è la
// frontiera dell'exactly-once — gli id processati non si riprocessano.

Limiti del canale (contratto duro): batch ingest ≤ 1000 eventi (413 BATCH_TOO_LARGE), NDJSON edge-audit ≤ 5000 righe. 503 code: DRAINING significa che il cloud si sta spegnendo — backoff, non allarme.

Il Flusso

txn: riga biz + audit + outbox ──commit──► il daemon legge ax_cdc_outbox
                                              │  batch (≤1000), ordinato per seq
                                              ▼
                              POST /sync/ingest  (Bearer edge api_key)
                                              │  dedup su id
                                              ▼
                                          cp_events ──► proiezioni in lettura
                                              │
                              ack → l'edge marca le entry consegnate
        cloud giù? le entry restano in coda, l'edge produce — offline-first

Ogni chiamata di sync autenticata tocca anche last_poll_at — l’heartbeat di flotta è un side-effect gratuito della consegna.

Esempio di Payload

# Il drain del daemon — esattamente ciò che manda, niente di più
curl -X POST https://cp.axiom-trace.eu/api/v1/sync/ingest \
  -H "Authorization: Bearer $EDGE_API_KEY" -H 'content-type: application/json' \
  -d '{"events":[{"id":"…","aggregate_type":"BIZ_CYCLES",
        "aggregate_id":"…","event_type":"INSERT_BIZ_CYCLES",
        "payload":{"cycle_seq":1042,"duration_ms":812},
        "created_at":"2026-09-26T14:01:03Z"}]}'

I Fallimenti Noti

Sintomo Causa → fix
401 su ingest API key ruotata al re-claim; la vecchia è invalida by design → riprovisiona
403 EDGE_CAP_EXCEEDED Tenant oltre il numero di edge licenziati → l’admin alza max_edges
413 BATCH_TOO_LARGE >1000 eventi → spezza; mai ritentare lo stesso batch sovradimensionato
429 Bucket ingest per-tenant → rispetta Retry-After, backoff con jitter
503 DRAINING Restart del cloud → ritenta dopo; allarmare su questo è un falso positivo
Eventi fermi in outbox Controlla i log del daemon e la rete — le righe sono al sicuro, la consegna è solo differita