Мы используем хранимые процедуры postgres 11 для циклического обновления строк в пакетах. После обновления пакета таблица «Ход выполнения» обновляется с указанием процента выполнения и статуса, ТО затем отправляется уведомление (с использованием pg_notify). Клиент nodejs прослушивает уведомление и обрабатывает его.
Для тестирования мы добавили PERFORM pg_sleep(5)
сразу после вызова pg_notify
, чтобы мы могли видеть, как медленно увеличивается процент выполнения.
Проблема в том, что уведомления не сразу отправляются слушателям при вызове PERFORM pg_notify
, а вместо этого ВСЕ уведомления отправляются ПОСЛЕ завершения хранимой процедуры.
Кто-нибудь сталкивался с этой проблемой и нашел какое-либо решение (кроме dblink)?
Мы попробовали следующее внутри хранимой процедуры:
- перемещено pg_sleep
в верхней части цикла
- добавление коммита; после pg_notify
- используйте notify channel, 'payload
вместо pg_notify
Затем мы попытались использовать триггеры + pg_notify
. Когда это не помогло, мы также попытались использовать execute format('notify channel, ''%s''', payload)
. Тот же результат.
Некоторые примеры кодов:
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 progress set percent= 70 where id = progress_id ;
commit;
perform pg_notify('progress_updates', '{"percent": 70}');
perform pg_sleep(5);
update progress set percent= 100 where id = progress_id ;
commit;
perform pg_notify('progress_updates', '{"percent": 100}');
END;
$$;
-- trigger
create or replace function notify_progress_trigger() returns trigger
language plpgsql
as
$$
DECLARE
payload TEXT;
BEGIN
raise notice 'TRIGGERED ON %', NOW();
payload := '{"percent": ' || NEW.percent || '}';
perform pg_notify('progress_updates', payload);
-- execute format('notify progress_updates, ''%s''', payload);
return NEW;
END;
$$;
alter function notify_progress_trigger() owner to postgres;
create trigger watched_progress_trigger
after insert or update
on operations
execute procedure notify_progress_trigger();
-- Call stored proc manually
call my_stored_proc();
Мы ожидали, что уведомления будут приниматься слушателем одно за другим после обновления каждого пакета во время выполнения хранимой процедуры, но вместо этого мы получаем все уведомления в быстрой последовательности после завершения хранимой процедуры.