Postgres通知未自动到达

时间:2016-10-07 23:17:59

标签: postgresql notifications observers

我在一个终端 A 中打开psql(Arch Linux上的PostgreSQL 9.5.4)并发出LISTEN "notif";

在另一个终端 B 中,我运行以下脚本(psql -f myscript.sql)。

这会创建一个包含两个触发器的表。如果在send为TRUE的情况下添加了一行,则触发一个触发器,如果​​更新了一行,则另一个触发器触发,使send从FALSE变为TRUE。两个触发器都发送通知。

DROP TRIGGER IF EXISTS do_notif ON notif;
DROP TRIGGER IF EXISTS do_notif2 ON notif;
DROP TABLE IF EXISTS notif;

CREATE TABLE notif (id INT PRIMARY KEY, send BOOLEAN, msg TEXT);

CREATE OR REPLACE FUNCTION post() RETURNS TRIGGER AS $$
BEGIN
    PERFORM pg_notify('notif', '+' || NEW.id::TEXT || ',' || coalesce(NEW.msg, '(null)'));
    RETURN NEW;
END $$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION post2() RETURNS TRIGGER AS $$
BEGIN
    PERFORM pg_notify('notif', '~' || NEW.id::TEXT || ',' || coalesce(NEW.msg, '(null)'));
    RETURN NEW;
END $$ LANGUAGE plpgsql;

CREATE TRIGGER do_notif AFTER INSERT ON notif
    FOR EACH ROW WHEN (NEW.send)
    EXECUTE PROCEDURE post();
CREATE TRIGGER do_notif2 AFTER UPDATE OF send ON notif
    FOR EACH ROW WHEN (NEW.send AND NOT OLD.send)
    EXECUTE PROCEDURE post2();

-- LISTEN "notif";

INSERT INTO notif VALUES (1, FALSE, 'update');
INSERT INTO notif VALUES (2, TRUE, 'insert');
UPDATE notif SET send = TRUE;
UPDATE notif SET send = FALSE;
UPDATE notif SET send = TRUE;

START TRANSACTION;
INSERT INTO notif VALUES (10, FALSE, 'a'), (11, TRUE, 'b'), (12, TRUE, 'c');
UPDATE notif SET send = TRUE WHERE id = 10;
COMMIT

我希望相关的INSERT和UPDATE查询应该会调用触发器,这些触发器会在终端 A 中接收发送通知。

这不会发生。我必须在终端 A 中再次手动运行LISTEN "notif";,这会立即向我提供缺少的通知。

如果我取消对该脚本中的LISTEN "notif";发表评论,那么运行该脚本的psql实例( B )会在相关位置向终端发送通知(在非事务性插入/更新之后将send设置为TRUE,并且在事务之后也是如此。

A 仍然不会显示这些内容,除非我在 A (或任何其他查询,例如LISTEN "notif";)中再次运行SELECT TRUE;。它不是一个终端缓冲问题,因为仅仅在 A 中点击ENTER不会导致通知出现。

PostgreSQL似乎不会立即通过不同的连接或不同的进程传递通知,但是当侦听器与生成通知的进程相同时,它会立即传递。

1 个答案:

答案 0 :(得分:3)

psql 在每个命令之后检查通知队列(更具体地说,在从服务器接收任何结果之后)。因此,您可以使用listen channel一次,每个后续命令都会检查是否有新通知。

基于 libpq.c 标准库的程序以相同的方式运行,在从服务器接收数据后检查通知队列the function PQnotifies。他们还有另一种可能性。如果在特定时间没有与服务器通信,则可以使用函数PQconsumeInput刷新通知队列。通过这种方式,他们以异步方式接收通知。司机的通知支持当然可以在更高层次上实施。