Skip to content

Pub/sub

Postgres has native support for pub/sub through LISTEN and NOTIFY commands. If you're not familiar, pub/sub stands for publish/subscribe and allows you to send and listen for arbitrary messages, in real time, by using Postgres as the message broker.

Historically, this feature was only available to clients which connect to Postgres directly. PgDog supports this in transaction mode, removing this limitation. You can use LISTEN and NOTIFY, as if you're connected directly to Postgres, with thousands of clients.

How it works

Pub/sub support is disabled by default and can be enabled by configuring the asynchronous message channel size in pgdog.toml:

[general]
pub_sub_channel_size = 4096
pubSubChannelSize: 4096

Clients can then start using Postgres LISTEN/NOTIFY commands like normal. PgDog will intercept and process them internally. How each command is handled is described below.

Pub/sub

Pub/sub architecture

LISTEN

When PgDog receives a LISTEN <channel> command, it will register itself with Postgres on the requested channel, on the client's behalf. It does that over a dedicated server connection. If multiple clients request to listen on the same channel, PgDog will register itself only once.

NOTIFY

When PgDog receives a NOTIFY <channel>, '<payload>' command, it will place it into an asynchronous queue and forward it to Postgres over a dedicated connection. This ensures that multiple instances of PgDog all receive the notification.

Once Postgres sends the notification back, PgDog will fan it out to all registered clients. If you have thousands of listeners, sending them a message is cheap since it's handled by a Tokio broadcast channel and not by Postgres.

Transactions

PgDog respects transactional guarantees offered by Postgres for notifications. If a notification is sent inside a transaction, it will be buffered until the transaction is committed and, only then, sent to Postgres.

If the transaction is rolled back or has an error, buffered notifications are dropped.

NOTIFY performance regression

This feature protects clients from sending NOTIFY commands to Postgres inside transactions, which has a known performance problem.

UNLISTEN

UNLISTEN <channel> removes the client from the list of clients interested in messages sent to that channel. It won't receive any more notifications, but PgDog continues to listen for them until all clients have unsubscribed or disconnected.

Once that happens, PgDog will send the UNLISTEN <channel> command to Postgres automatically.

Trade-offs

Since PgDog handles all commands, clients will get an immediate acknowledgement as soon as it processes a command. However, it doesn't mean that the command is immediately sent to Postgres. If the is a large backlog in the background queue, it could take a few milliseconds for a command to be forwarded to the server.

The size of the backlog is controlled with the pub_sub_channel_size setting. Once the queue is full, clients will begin to wait until the commands are processed.

Delivery guarantees

LISTEN and UNLISTEN messages are guaranteed to be delivered. A client will, eventually, start receiving notifications on a channel. If there are a lot of requests in the queue, this may take a little while (a few milliseconds, typically).

A NOTIFY message can be lost if the dedicated connection to Postgres is broken. PgDog will not attempt re-delivery for a message on connection error. This is done to avoid duplicate notifications and follows the "at most once" guarantee principle.

If this happens, PgDog will attempt to re-establish the connection immediately. All subsequent messages will be delivered over the new connection.