Actors/Packages/Postgres/API reference
@sigx/actors-pg · Preview

API reference#

Exports of @sigx/actors-pg v0.7.0.

Providers#

ExportReturnsRole
pgCluster(options)ClusterProvidersmembership + directory
pgMembership(pool, options?)ClusterMembershipliveness on the database clock
pgDirectory(pool, options?)ActorDirectorysingle-activation claims
pgStorage(options)ActorStorageetag-CAS text rows
pgReminders(options)ActorRemindersSKIP LOCKED durable reminders

Schema helpers#

TypeScript
// ensurePgSchema(pool: PgPoolLike, options?: { schema?: string }): Promise<void>
// pgSchemaSql(schema?: string): string

await ensurePgSchema(pool);                  // issues the DDL under an advisory xact lock
await ensurePgSchema(pool, { schema: 'app' });

console.log(pgSchemaSql());                  // returns it, for your migration tool

Encoding helpers#

pgText(value) and pgTextDecode(value) — the text encoding used for stored values, exported for tooling that needs to read or write the tables directly.

Types#

PgQueryable, PgPoolLike, PgClusterOptions, PgStorageOptions, PgRemindersOptions.

Table layout#

All under the configured schema, sigx by default.

SQL
state(type, key, etag, state)                       -- state is text
directory(actor_id, host_id, activation_id)         -- + directory_host_id index
hosts(host_id, descriptor, expires_at)
membership_version(id, version)
reminders(type, key, name, next_due, period_ms)     -- + reminders_due index

Semantics worth knowing#

Etags are client-minted UUIDs, equality-compared only. Every CAS is a single statement whose row count is the verdict — no transactions, no advisory locks.

State is text, not jsonb — deliberately. Actor state may contain NUL, which jsonb rejects outright, so the column stores the encoded string verbatim and Postgres never parses it. A top-level array state therefore cannot be silently coerced into a Postgres ARRAY either.

Directory entries carry no TTL. There is one heartbeat per host, not per activation; entry validity is the owner's liveness in the membership view, and the storage etag CAS remains the integrity floor underneath.

Membership change detection compares host signatures, not just the version counter — a host that dies silently expires on the database clock without anyone bumping a version, and views still converge.

Push is best-effort. LISTEN rides a connection checked out of the pool; if the pool cannot dedicate one, or the connection drops, the poll is the guarantee and pollMs is the propagation bound.

Reminders commit before delivery. The advance-or-delete is committed before the handler runs, which is what makes delivery at-most-once and prevents catch-up bursts after an outage.

Next steps#