Multi-node PostgreSQL persistence for the MCP Tasks extension.
This adapter accepts an application-owned Ecto.Repo; it never starts a
repository or runs migrations. Task snapshots and their serializable work
descriptors are stored atomically as versioned JSONB. Applied events are
committed to a separate ledger in the same transaction as the aggregate
update.
Claims use PostgreSQL row locks, database time, opaque UUID tokens, exact
expiry matching, and monotonically increasing generations. Recovery uses
FOR UPDATE SKIP LOCKED, allowing independently supervised runners on
several nodes to consume the same queue without a coordinator process.
Recovery remains at least once. Applications must deduplicate external side
effects with Snodo.Extensions.Tasks.Work.idempotency_key.
create/4 refuses a task with {:error, {:capacity_exceeded, limit}} when
the table already holds :max_tasks tasks (default 10,000) or the caller's
scope already has :max_active_tasks_per_scope working or input-required
tasks (default 100). Either may be :infinity. The counts are taken inside
the creating transaction under a transaction-scoped advisory lock, so
concurrent creations on several nodes cannot pass a limit together; setting
both limits to :infinity skips the lock and the counts. An expired task
counts until it is reaped.
reap/1 deletes at most :reap_batch_size expired tasks per call (default
500). A runner calling it every :reap_interval_ms therefore removes at most
that many tasks per interval.
Summary
Functions
Audits a bounded page of aggregates and event ledgers without mutating them.
Checks that the application has run this adapter's current migration.
Returns applied event history through the same scoped read authority as get/3.
Builds immutable adapter configuration around an application-owned Repo.
Builds adapter configuration or raises ArgumentError.
Types
@type audit_report() :: %{ checked: non_neg_integer(), errors: [map()], next_cursor: String.t() | nil }
Functions
@spec audit(Snodo.Extensions.Tasks.Store.Postgres.Config.t(), keyword()) :: {:ok, audit_report()} | {:error, term()}
Audits a bounded page of aggregates and event ledgers without mutating them.
@spec check_schema(Snodo.Extensions.Tasks.Store.Postgres.Config.t()) :: :ok | {:error, term()}
Checks that the application has run this adapter's current migration.
@spec history(Snodo.Extensions.Tasks.Store.Postgres.Config.t(), String.t(), term()) :: {:ok, [map()]} | :not_found | {:error, term()}
Returns applied event history through the same scoped read authority as get/3.
@spec new(keyword()) :: {:ok, Snodo.Extensions.Tasks.Store.Postgres.Config.t()} | {:error, term()}
Builds immutable adapter configuration around an application-owned Repo.
@spec new!(keyword()) :: Snodo.Extensions.Tasks.Store.Postgres.Config.t()
Builds adapter configuration or raises ArgumentError.