立即获得 Postgres NOTIFY 通知

问题描述 投票:0回答:1

DBD::Pg 有什么方法可以阻塞等待消息准备好后立即返回的 NOTIFY 吗?

我有一个简单的测试脚本,可以使用 Postgres 的“通知”机制发送消息:

#!/usr/bin/perl

use 5.018;
use strict;
use warnings;
use autodie;

use DBI qw();

$| = 1;  # Flush buffer on print
my $dsn = 'dbi:Pg:dbname=test';
my $attr = {
    AutoCommit  => 0,
    RaiseError  => 1,
    PrintError  => 0,
};
my $topic = 'test_topic';

my $dbh = DBI->connect($dsn, '', '', $attr);

while (1) {
    print "payload: ";
    chomp(my $payload = <>);
    $dbh->do("NOTIFY $topic, '$payload'");
    $dbh->commit;
}

我还有一个简单的接收器脚本,它使用 LISTEN 来订阅消息:

#!/usr/bin/perl

use 5.018;
use strict;
use warnings;
use autodie;

use DBI qw();

$| = 1;  # Flush buffer on print
my $dsn = 'dbi:Pg:dbname=test';
my $attr = {
    AutoCommit  => 0,
    RaiseError  => 1,
    PrintError  => 0,
};
my $topic = 'test_topic';

my $dbh = DBI->connect($dsn, '', '', $attr);
$dbh->do("LISTEN $topic");

while (1) {
    $dbh->commit();
    while(my $notify = $dbh->pg_notifies) {
        my($topic, $pid, $payload) = @$notify;
        say "Got message: $topic => $payload";
    }
    sleep(10);
}

问题是

$dbh->pg_notifies
不会阻塞,所以如果没有排队的通知,它会立即返回
undef
。我已经放置了
sleep(10)
,这样它就不是一个繁忙的循环,但这当然意味着我在发送 NOTIFY 消息后但在我的 LISTEN 收到它之前会有最多 10 秒的延迟。

一些搜索建议在

libpq
级别,您可以在套接字上执行
select
以立即通知传入的NOTIFY,所以我尝试了这个:

my $sock_fd = $dbh->{pg_socket};
my $read_set = '';
vec($read_set, $sock_fd, 1) = 1;

while (1) {
    $dbh->commit();
    while(my $notify = $dbh->pg_notifies) {
        my($topic, $pid, $payload) = @$notify;
        say "Got message: $topic => $payload";
    }
    select($read_set, undef, undef, 10);
}

但它似乎不起作用,

select
似乎只在我的 10 秒超时到期时才返回。

在我看来,NOTIFY/LISTEN 提供了一种避免轮询循环的方法,但我似乎无法在没有轮询循环的情况下使其工作。有什么建议吗?

perl select notify listen dbd-pg
1个回答
0
投票

问题是 $read_set 可能在第一次 select() 调用后就被破坏了。您应该将其替换为:

select(my $read_out = $read_set, undef, undef, 10);

在第一次调用之后,您可能不会收到通知,因此您会得到一个空的 fd 集,下次您使用空集调用 select 时,这就是为什么您需要将 $read_set 复制到另一个变量中。

© www.soinside.com 2019 - 2024. All rights reserved.