Получите немедленное уведомление о Postgres УВЕДОМЛЕНИЕ - PullRequest
0 голосов
/ 03 сентября 2018

Есть ли способ с DBD :: Pg сделать блокировку ожидания для 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), чтобы он не был занятым, но, конечно, это означает, что я получаю задержку до 10 секунд после отправки сообщения NOTIFY, но до того, как мой LISTEN его получит.

Некоторые поиски показали, что на уровне 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 предоставляет способ избежать циклов опроса, но я не могу заставить его работать без цикла опроса. Предложения?

...