Postgres notifications listener for pg-promise (v10 or newer), featuring:
- Automatic reconnections, with the help of retry-async
- No external dependencies
$ npm i pg-listener
Peer dependency pg-promise is used underneath here, which you need to include in your project.
import pgPromise from 'pg-promise';
import {PgListener, IListenEvents} from 'pg-listener';
const pgp = pgPromise();
const db = pgp({
user: 'user-name',
database: 'db-name',
// etc.
keepAlive: true
});
const ls = new PgListener({pgp, db});
const events: IListenEvents = {
onMessage(msg) {
console.log(msg); //=> {channel,length,payload,processId}
}
// See also: onConnected, onDisconnected, onFailedReconnect
};
// listen to 2 channels on one connection:
ls.listen(['channel_1', 'channel_2'], events)
.then(result => {
// Successful Initial Connection;
// result = {createIterable, cancel, notify, etc.}
})
.catch(err => {
// Failed Initial Connection
});Alternatively, you can process notifications via an iterable object:
const result = await ls.listen(['channel_1', 'channel_2']);
for await (const msg of result.createIterable()) {
console.log(msg);
}See also:
- API: listen => IListenResult
- More examples
Internally, the library makes use of retry-async to retry connecting. You can set RetryOptions via properties retryAll and retryInit when creating the listener:
const ls = new PgListener({
pgp, db,
retryAll: {
delay: s => (s.index + 1) * 1000, // +1s delay for each retry
retry: 5 // retry up to 5 times
}
});Above, retryAll is for both initial and later connection attempts, while retryInit sets/overrides it
specifically for the initial connection if you want it to be different. When those options are not specified, the
library uses
internal retryDefault that's defined like this:
const retryDefault: RetryOptions = {
retry: 5, // up to 5 retries
delay: s => 5 ** (s.index + 1) // Exponential delays: 5, 25, 125, 625, 3125 ms
};Database-connection options keepAlive / keepAliveInitialDelayMillis can be used with listeners to prevent the
connection from dying after not receiving any events for an extended period of time. This is particularly important
with such hosting environments as AWS. Check node-postgres driver for details.
This library allows passing an empty list of channels into the listen method to create and maintain a connection
just for sending notifications. However, in the real world, this is hardly ever needed, because it is only LISTEN that
needs a robust connection, while NOTIFY does not, i.e. you can send NOTIFY right from the database
root object, without using this library:
await db.none('NOTIFY $(channel:alias), $(payload)', {
channel: 'my_channel_name',
payload: 'some payload text'
});That's why notify here is inside the result from listen method, as a convenience for sending notifications through the same connection as we do the listening, but with a simpler syntax.
Check out the Performance Test to see how fast PostgreSQL can loop through notifications.
Example of integration with RxJs:
import {from} from 'rxjs';
const r = await ls.listen(['channel_1', 'channel_2']);
from(r.createIterable())
.subscribe(msg => {
console.log(msg);
});See also the examples.