Skip to main content
Version: 0.3.16

Pub/Sub — LISTEN / NOTIFY

xcon-db carries a pub/sub backbone and exposes it with PostgreSQL's own syntax, over the same pg-wire connection your queries use:

LISTEN jobs; -- subscribe this connection
NOTIFY jobs, 'payload'; -- publish (from any session in the database)
UNLISTEN jobs; -- or UNLISTEN * for everything

Notifications arrive as standard asynchronous messages — psql prints them, pgx exposes WaitForNotification, libpq PQnotifies. No extra port, no extra client.

Events are wakeup signals​

An event tells you that something changed, never what the truth is. There is no replay: a connection that was away pulls the current state first (SHOW SESSIONS, SHOW LOGS, a feed query by x_rev), then listens. A slow consumer's events are dropped rather than ever slowing a publisher — correctness always lives in the pull that follows the wakeup, so a dropped event costs staleness, not wrongness.

System channels​

The x_ prefix belongs to the engine — you can LISTEN to these, never NOTIFY them:

ChannelScopePayloadWho
x_logsnode{"seq":…,"ts":…,"level":…,"message":…} — every log-ring entryadmin
x_sessionsnode{"event":"connect"|"disconnect"|"statement", …}admin
x_databound database{"table":…,"rows":N} — coalesced: at most one event per table per 250 ms window, however hot ingest runsdatabase user / bound admin
x_ddlbound database{"stmt":…} — schema changes; a migration's shadow stays silent, COMMIT MIGRATION rings oncedatabase user / bound admin
x_jobsbound database{"job":…,"phase":…,"rows":N,…} — background job progress, e.g. an importdatabase user / bound admin

User channels​

Any other channel name is yours. Channels are database-local: the tenancy wall holds for events exactly as it does for rows — NOTIFY jobs in one database is invisible to every other, whatever the name. Channels come to exist on first use; LISTEN before the first NOTIFY works.

-- session A (worker)
LISTEN jobs;

-- session B (producer)
NOTIFY jobs, '{"kind":"import","file":"batch-7.csv"}';

The sync pattern​

The intended shape for cache/sync clients (this is how xcon studio's monitors work):

  1. Photograph — pull the current state through your cursor (SELECT … WHERE x_rev > :watermark, or SHOW SESSIONS).
  2. Listen — LISTEN x_data; and wait.
  3. On wakeup, pull again — the event carries no rows on purpose; your cursor does the truthful reading.

A reconnect just repeats step 1 — nothing is lost, because nothing was entrusted to the stream.