LISTEN / NOTIFY / UNLISTEN
NodeDB implements PostgreSQL-compatible asynchronous notifications over pgwire. A client subscribes to a collection and receives a notification message every time a row in that collection is mutated by a committed transaction.
Subscribing
LISTEN <collection>;
After this command the connection enters a listening state for the named collection. Multiple collections can be listened on the same connection.
LISTEN orders;
LISTEN inventory;
Unsubscribing
-- Stop listening to a specific collection
UNLISTEN orders;
-- Stop listening to all collections on this connection
UNLISTEN *;
Sending a manual notification
NOTIFY <channel>, '<payload>';
NOTIFY sends an arbitrary text payload to all connections currently listening on the named channel. The channel name does not have to be an existing collection — it is just a string label.
NOTIFY alerts, 'deployment started';
NOTIFY user_events, '{"user_id": "u1", "event": "login"}';
Receiving notifications
Notifications are delivered as PostgreSQL NotificationResponse messages. In psql they appear immediately after the triggering transaction commits:
Asynchronous notification "orders" with payload "" from server process with PID 12345.
Most PostgreSQL client libraries expose an async notification callback:
# Python (psycopg2)
conn.set_isolation_level(0) # autocommit required for LISTEN
cur.execute("LISTEN orders")
while True:
select.select([conn], [], [])
conn.poll()
while conn.notifies:
notify = conn.notifies.pop()
print(f"channel={notify.channel} payload={notify.payload}")
Transaction semantics
Notifications triggered by collection mutations are buffered until COMMIT and dropped on ROLLBACK.
BEGIN;
INSERT INTO orders (id, total) VALUES ('o1', 99.99); -- notification queued, not sent yet
COMMIT; -- notification delivered now
BEGIN;
INSERT INTO orders (id, total) VALUES ('o2', 50.00);
ROLLBACK; -- notification dropped, never sent
This guarantees that listeners never see notifications for writes that were rolled back.
Tenant scoping
Notifications are tenant-scoped. A connection authenticated to tenant acme only receives notifications for mutations within the acme tenant. A connection cannot receive notifications for a different tenant's collections, even if it knows the collection name.
Notification payload
For collection-mutation notifications the payload is empty by default. The full change data is available via Change Streams if you need the actual before/after row values.
NOTIFY <channel>, '<payload>' delivers the payload string exactly as provided.
Notes
LISTENsubscribes to a collection name, not an arbitrary string channel. Listening on a name that does not correspond to an existing collection returns no error but will never fire.- The connection must remain open to receive notifications — notifications are not queued for reconnection.
- A single connection can listen on multiple collections simultaneously.
NOTIFYwithout a payload (NOTIFY channel) is not supported; the payload argument is required.