HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

postgres notifications from inside stored procedures/triggers not immediately received by node.js listener client

Submitted by: @import:stackexchange-dba··
0
Viewed 0 times
storedprocedurespostgresnotnodelistenernotificationsclientreceivedfrom

Problem

We are using postgres 11's stored procedures to do looped update of rows in batches. After a batch is updated, a 'progress' table is updated with progress percent and status, THEN a notification (using pg_notify) is sent. A nodejs client listens for the notification and handles it.

For testing, we added PERFORM pg_sleep(5) right after pg_notify call so we can see the progress percent slowly increment.

The problem is the notifications aren't sent immediately to listeners when PERFORM pg_notify is called but instead ALL notifications are sent AFTER the stored procedure has completed running.

Has anyone encountered this problem and found any solution (aside from dblink)?

We've tried the following inside the Stored Procedure:
  • moved pg_sleep at top of loop
  • adding commit; after pg_notify
  • use notify channel, 'payload instead of pg_notify



We then tried using triggers + pg_notify. When that didn't work we also tried using execute format('notify channel, ''%s''', payload). The same result.

Some sample codes:

Node.js

const pg = require('pg');
let client = new pg.Client({user: '', database: '', host: '', password: '', port: 5432});
client.connect();
client.query('LISTEN progress_updates');
client.on('notification', function(data) {
   console.log('notification: ', data);
});


Backend:

```
-- table
drop table if exists operations;
create table progress ( id serial primary key, percent int default 0 );

-- stored procedure
CREATE OR REPLACE PROCEDURE my_stored_proc() language plpgsql
AS $$
DECLARE
progress_id int;
BEGIN
insert into progress (percent) values (0) returning id into progress_id;
commit;

update progress set percent= 10 where id = progress_id ;
commit;
perform pg_notify('progress_updates', '{"percent": 10}');
-- notify progress_updates, '{"percent": 10}'
perform pg_sleep(5);

update progress set percent= 30 where id = progress_id ;
commit;
perform pg_notify('progress_updates', '{"percent": 30}');
perform pg_sleep(5);

update prog

Solution

As far as I'm aware what you're trying to do, by issuing a commit inside a procedure, is use an autonomous transaction. Postgres does not support them inside stored procedures/functions, and the behaviour you are seeing is correct - the (implicit) transaction does not complete until the procedure completes.

This page discusses the issue in detail along with potential workarounds.

Context

StackExchange Database Administrators Q#236578, answer score: 2

Revisions (0)

No revisions yet.