Files
2026-05-27 23:29:53 +01:00

7.4 KiB

@suaveplan/api-2pc - Two-phase commit coordinator for the Suaveplan API plugin system.

Two-phase commit coordinator for the Suaveplan API plugin system. Drives Postgres PREPARE TRANSACTION / COMMIT PREPARED / ROLLBACK PREPARED across registered participants with a host-owned ledger in suaveplan_2pc_transactions. Refuses non-preparable engines as writers (SQLite, SurrealDB) but accepts them as read-only voters. Default timeoutMs 5000, hard ceiling 30000, default outstanding-prepared cap 256, all operator-tunable. Ships boot-time orphan resolution via pg_prepared_xacts, the full TWOPC_* error namespace, OTel transaction/prepare/commit/rollback spans plus prepare_duration_ms / commit_duration_ms histograms / transactions_total counter / outstanding_prepared gauge, and run2pcParticipantConformance on the ./testing subpath. Server-tier — Bun + Node.

Postgres-only writer surface. SQLite and SurrealDB cannot honour PREPARE TRANSACTION and are refused as writers at install time. They MAY participate as read-only voters that contribute a commit/abort vote based on their own consistency check, but the coordinator never sends them prepare / commit / rollback SQL.

Documentation tree

  • coordinator — Top-level orchestration for the 2PC protocol. createTwoPcCoordinator builds a fully-wired coordinator that holds a pa…
    • coordinator — Top-level orchestration for the 2PC protocol. createTwoPcCoordinator builds a fully-wired coordinator that holds a pa…
  • error-codes — This module owns the TWOPC_* error-code namespace and the TwoPcError concrete class for the @suaveplan/api-2pc pa…
    • error-codes — This module owns the TWOPC_* error-code namespace and the TwoPcError concrete class for the @suaveplan/api-2pc pa…
  • instruments — Builds the OTel instrument registry the 2PC coordinator emits against on every transaction. Each instrument's name foll…
    • instruments — Builds the OTel instrument registry the 2PC coordinator emits against on every transaction. Each instrument's name foll…
  • outstanding-cap — Admission control for in-flight 2PC transactions. The coordinator holds a fixed-size budget of "outstanding prepared tr…
  • timeout-ceiling — Enforces the hard 30 000 ms ceiling on caller-supplied timeoutMs values. The check fires at the public entry point of…
  • options — Defines the boundary-validated option shape consumed by createTwoPcCoordinator. Every tunable that affects coordinato…
    • options — Defines the boundary-validated option shape consumed by createTwoPcCoordinator. Every tunable that affects coordinato…
  • persistence — Persists every coordinator state transition into the suaveplan_2pc_transactions ledger table. The table is owned by `…
    • persistence — Persists every coordinator state transition into the suaveplan_2pc_transactions ledger table. The table is owned by `…
  • commit — Phase-2 commit for a single participant. Once every participant has returned commit from phase 1 and the coordinator…
  • gid — Builds and parses the global transaction id (gid) string passed to Postgres' PREPARE TRANSACTION '<gid>'. The format…
  • prepare — Implements phase 1 of the 2PC protocol for a single participant. The coordinator iterates participants and calls this m…
  • rollback — Phase-2 rollback for a single participant. Used both by the coordinator's abort path (vote_abort or prepare failure) an…
  • recovery — Boot-time orphan resolution for the 2PC coordinator. When a host crashes between phase 1 and phase 2, prepared transact…
    • recovery — Boot-time orphan resolution for the 2PC coordinator. When a host crashes between phase 1 and phase 2, prepared transact…
  • registry — The participant registry is the install-time admission control between plugins and the 2PC coordinator. Plugins declare…
    • participant-registry — The participant registry is the install-time admission control between plugins and the 2PC coordinator. Plugins declare…
  • testing — Provides run2pcParticipantConformance(factory) — a runnable test suite that pins the contract every 2PC writer partic…
    • conformance — Provides run2pcParticipantConformance(factory) — a runnable test suite that pins the contract every 2PC writer partic…

Why

Some cross-database workflows demand atomic visibility — no partial state, no eventual convergence. Per the API Plugin Foundation design doc §9.2 the coordinator runs phase-1 prepare across every registered participant, persists the vote tally to suaveplan_2pc_transactions on the host's metadata DB, then issues COMMIT PREPARED or ROLLBACK PREPARED against every writer participant. Recovery on the next boot resolves any prepared transactions left over from a host crash.

Modules

  • coordinator/ — createTwoPcCoordinator + run2pc factory and state machine.
  • registry/ — TwoPcParticipantRegistry (admission control).
  • phases/ — preparePhaseOne, commitPhaseTwo, rollbackPhaseTwo, gid helpers.
  • persistence/ — TwoPcLedgerStore over the host-owned suaveplan_2pc_transactions table.
  • recovery/ — boot-time orphan resolution via pg_prepared_xacts.
  • limits/ — OutstandingPreparedCap (admission), assertTimeoutBelowCeiling (per-call ceiling).
  • instruments/ — OTel meter/tracer bundle.
  • options/ — Zod-validated coordinator options + defaults.
  • error-codes/ — 10 TWOPC_* codes + TwoPcError.
  • types/ — Run2PcInput, Run2PcOutcome, participant + state types.
  • testing/ — run2pcParticipantConformance(factory) suite.

Quick start

import { createTwoPcCoordinator } from "@suaveplan/api-2pc";

const coordinator = createTwoPcCoordinator({
    options: { hostInstanceId: "host-01" },
    registry,
    ledgerDb,
    clock: () => Date.now(),
    idGenerator: () => crypto.randomUUID(),
});

const outcome = await coordinator.run2pc({
    participants: [
        { id: "billing", input: { invoiceId: "inv-1" } },
        { id: "inventory", input: { sku: "abc-9" } },
    ],
});
// outcome.state is "committed" | "aborted" | "in_doubt"

Defaults

  • timeoutMs: 5000 (operator-tunable per-call up to the 30000 ms ceiling).
  • outstandingPreparedCap: 256 (operator-tunable via host config).

Error namespace

Every production code path throws TwoPcError with one of the ten TWOPC_* codes. See src/error-codes/error-codes.md for the full catalogue.

Conformance

Every adapter implementing a writer participant MUST run run2pcParticipantConformance({ create: ... }) in a tests/conformance/run-2pc-participant.test.ts file. The harness pins prepare / commit / rollback semantics and the idempotency contract.