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在套接字上执行一个以立即收到传入通知的通知,所以我尝试了这个:

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 提供了一种避免轮询循环的方法,但我似乎无法在没有轮询循环的情况下使其工作。建议?

4

0 回答 0