Postgres
For the team whose one durable store is SQL. Four providers, one pool — and the only shipped backend that covers reminders as well.
Installation
pnpm add @sigx/actors-pg pgpg (node-postgres) ≥ 8 is a peer dependency; Postgres ≥ 13.
The four providers
pgStorage() — etag-CAS ActorStorage: one row per actor, no
TTL. A conflict throws the branded ActorStorageConflict the runtime turns into
fault-and-reload.
pgMembership() — TTL-heartbeat membership with expiry judged on the database clock,
so host clock skew cannot fake a death or a survival. LISTEN/NOTIFY push with a poll fallback,
and self-suspect fencing when a host cannot prove its own membership.
pgReminders() — durable reminders on an indexed table. A tick is one
FOR UPDATE SKIP LOCKED claim statement for exactly the due rows, and the advance or delete
commits before delivery — at-most-once, no catch-up bursts, database clock throughout.
Every host may tick the same table, because row locks replace shard ownership.
pgDirectory() — the single-activation claim directory: create-if-absent claim,
compare-and-delete release and evict, plus an evictHost sweep for departed hosts.
pgCluster() bundles membership and directory.
Why you might pick it over Redis
- You already run Postgres and would rather not add Redis.
- Reminder tables get large. The
SKIP LOCKEDdesign is the scan answer; Redis rides storage with 16 hash shards, which is fine until it is not. - Clock skew worries you. Expiry on the database clock removes a whole class of split-brain question.
DDL is explicit
The providers never issue DDL, so a production role needs only DML grants.
await ensurePgSchema(pool); // dev and tests
// production: run pgSchemaSql() through your migration tool
Next steps
- Installation — schema, wiring and options.
- API reference — exports and table layout.
- Clustering — where the providers plug in.
