DBD::P g有什么方法可以阻止等待消息准备就绪时立即返回的NOTIFY?
我有一个简单的测试脚本,可以使用Postgres"NOTIFY"机制发送消息:
#!/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
,以立即收到传入通知的通知,所以我尝试了这个:
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 提供了一种避免轮询循环的方法,但我似乎无法在没有轮询循环的情况下使其工作。 建议?
问题是 $read_set 可能在第一次 select(( 调用后就被毁了。您应该将其替换为以下内容:
select(my $read_out = $read_set, undef, undef, 10);
在第一次调用之后,您可能还不会收到通知,因此您会返回一个空的 fd 集,下次使用空集调用 select 时,这就是为什么您需要将 $read_set 复制到不同的变量中。