@demystify/events
v0.3.0
Published
Fault-tolerant Postgres-native job/event pipeline: transactional outbox, idempotent consumers, retries with backoff+jitter, DLQ.
Downloads
443
Readme
@demystify/events
Durable jobs and events for TypeScript — Postgres-backed (pgmq) with a transactional outbox, idempotent consumers, exponential backoff + full jitter retries, and a dead-letter queue. Ships a full-fidelity in-memory driver and an optional PGlite subpath so the same code runs offline with no database.
Part of the Demystify Core Services
suite. A matching Python package, demystify-events,
mirrors this API.
Install
npm add @demystify/events
# or: pnpm add @demystify/eventsQuickstart (offline, no database)
import { createEventsClient } from "@demystify/events";
import { MemoryQueueDriver } from "@demystify/events"; // in-memory, full semantics
const client = createEventsClient({ driver: new MemoryQueueDriver() });
await client.enqueue("email.send", { to: "[email protected]" });
// idempotent, retried with backoff+jitter, DLQ on poison
await client.work("email.send", async (ctx, job) => {
// effects committed in the same transaction as the ack
});For real Postgres, use the PgmqQueueDriver + PgExecutor adapters with a
connection pool. For SQL-real tests without a server, import the ./pglite
subpath.
Postgres requirements
PgmqQueueDriver runs on the pgmq Postgres
extension. It must be installed in the target database before the driver is
used:
CREATE EXTENSION pgmq;Stock postgres images do not ship pgmq — use an image that does:
ghcr.io/demystify-systems/postgres-pgvector-pgmq— ours; pgvector + pgmq combinedquay.io/tembo/pg16-pgmq— Tembo's Postgres 16 + pgmq image
If the extension is missing, the driver fails fast with an actionable error
instead of the cryptic relation "pgmq.q_x" does not exist:
pgmq extension not available in this database. Run CREATE EXTENSION pgmq;
(requires a Postgres image that ships pgmq — e.g.
ghcr.io/demystify-systems/postgres-pgvector-pgmq or quay.io/tembo/pg16-pgmq).
See the @demystify/events README, 'Postgres requirements'.The original Postgres error is preserved as the thrown error's cause.
Choosing a driver
| Driver | Durability | Intended use |
| -------------------------------------------- | ---------------------------------------------- | ---------------------------------- |
| MemoryQueueDriver / EphemeralQueueDriver | None — process memory, jobs lost on restart | Tests, demos |
| PgmqQueueDriver | Durable — Postgres (pgmq extension) | Production |
| ./pglite subpath | Durable within a file/dir (embedded Postgres) | Local/offline SQL-real tests |
EphemeralQueueDriver is the preferred, self-describing alias for
MemoryQueueDriver — the same class, named so nobody ships process memory
as durable delivery by accident.
To keep the footgun visible, constructing the in-memory driver logs a
console.warn once per process:
[@demystify/events] MemoryQueueDriver is EPHEMERAL (jobs lost on restart) — fine for
tests/demos, not for durable delivery. Use PgmqQueueDriver in production, or set
DMSTFY_EVENTS_ALLOW_EPHEMERAL=1 to silence.The warning is suppressed automatically under test runs (NODE_ENV=test or
vitest's VITEST env marker). If you run the in-memory driver on purpose
outside tests (demos, kiosks, scratch tooling), set
DMSTFY_EVENTS_ALLOW_EPHEMERAL=1 to silence it.
Exports
createEventsClient/EventsClient— enqueue, transactional enqueue, workers, relaycontractBackoff,fullJitterBackoff,DEFAULT_BACKOFF— retry schedulesRelayWorker— transactional outbox relay (SKIP LOCKED)validateSchema— JSON-schema event-contract validation- Ports:
QueueDriver,Sql,Tx,SqlExecutor - Adapters:
MemoryQueueDriver(aliasEphemeralQueueDriver),PgmqQueueDriver,PgExecutor(+./pglite) VERSION— the published package version string
See the module README
for the delivery guarantees, chaos-test results, and the /ops/v1 API.
License
MIT © Demystify Systems
