当 PostgreSQL 中没有会话发出 LISTEN 时,NOTIFY 会发生啥?

Posted

技术标签:

【中文标题】当 PostgreSQL 中没有会话发出 LISTEN 时,NOTIFY 会发生啥?【英文标题】:What happens with a NOTIFY when no session has issued LISTEN in PostgreSQL?当 PostgreSQL 中没有会话发出 LISTEN 时,NOTIFY 会发生什么? 【发布时间】:2014-05-30 00:31:18 【问题描述】:

PostgreSQL 有一个很好的监听/通知系统。 Documentation 说:

有一个队列保存已发送但未发送的通知 尚未由所有收听会话处理。如果这个队列满了, 调用 NOTIFY 的事务将在提交时失败。

但我无法找出没有侦听器的指定频道中的事件发生了什么。通知队列会溢出还是 PG 会从队列中删除这些事件?

【问题讨论】:

那么如果周围没有人,基本上一棵树就不会倒在森林里? 对不起,我听不懂你在说什么。我的问题不正确吗? 如果没有监听器,那么每条消息都已经被所有监听器处理过了。 PostgreSQL 在这种情况下不会像@IfLoop 建议的那样做任何事情。你可以试试:NOTIFY non_existing_channel; 好吧,如果我在喝咖啡休息的时候问一个空房间里的每个人是否要喝咖啡,我要等多久才能得到房间里每个人的回答?. “所有听众”与“至少一个听众”不同, 【参考方案1】:

手册中可能会更清楚,但有明确的指示表明,一旦没有会话正在积极等待通知,队列就会被清除。 Per documentation:

但是,如果会话执行 LISTEN 然后进入 交易了很长时间。队列半满后,您将看到警告 在将您指向阻止清理的会话的日志文件中。在这种情况下 您应该确保此会话结束其当前事务,以便 清理工作可以继续进行。

这意味着,如果没有人在监听(没有活动会话在同一通道上发出 LISTEN 命令),没有什么可以阻止 Postgres立即清理队列。

【讨论】:

有什么办法可以解决这个缺点吗?如果目前没有进程正在监听但将来可能会丢失任何通知,我不想丢失任何通知?我们可以保留未被收听的通知吗? @Zoran777:除了NOTIFY,您还可以写入日志表。每个会话仅接收在它注册了LISTEN 频道之后 发出的通知。由于 pg 9.2 也没有办法获得“听众名单”。请参阅here 和here 还有其他一些优点。您可能会开始一个包含详细信息的新问题。您可以随时链接到这个以获取上下文。【参考方案2】:

当已发出NOTIFY 的事务提交时,SQL 引擎会查找LISTEN此时的其他会话以获取此通知。

如果没有,则丢弃通知。它没有在任何地方排队。

它并没有像LISTEN documentation 那样直接解释,但正如@IfLoop cmets 所指出的,它通过严格解释来暗示:

...保存已发送但尚未发送的通知的队列 由所有监听会话处理。

零会话尚未处理意味着没有什么可以排队。

这也是有道理的,因为否则每个通知者都应该担心是否有听众,这将严重妨碍NOTIFY的有用性。

【讨论】:

更糟。如果有一个听众,但应该有两个怎么办?发件人无法知道。发送者只能期望它知道的许多接收者。如果没有,则消息可以立即被丢弃。

以上是关于当 PostgreSQL 中没有会话发出 LISTEN 时,NOTIFY 会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何检查 PostgreSQL 事务中的待处理操作

我可以要求 Postgresql 忽略事务中的错误吗

如何检查PostgreSQL事务中的挂起操作

如果我们从设置中有 Facebook 会话,FBLoginView 不会发出警报

org.postgresql.util.PSQLException:协议错误。会话设置失败

SilverStripe 功能测试是不是在发出 post 请求后将数据保存在会话中