1

我正在使用Mojolicious和一个名为pgAsync的插件来监听从Postgres数据库NOTIFY发出的事件。我目前拥有的代码运行良好,但我看到数据库连接的数量只会不断增加。

后端

#!/usr/bin/env perl

use Mojolicious::Lite;
use Mojo::IOLoop;
use Mojolicious::Plugin::PgAsync;

app->secret('awdawdawdawd');

plugin PgAsync => {dbi => ['dbi:Pg:dbname=;host=;port=;', '', '', {AutoCommit => 0, RaiseError => 1}]};

any '/api/listen' => sub {
  my $self = shift;

  my $saved_tx = $self->tx;

  Mojo::IOLoop->stream($self->tx->connection)->timeout(300);

  $self->res->headers->add('Content-Type' => 'text/event-stream');
  $self->res->headers->add('Cache-Control' => 'no-cache');
  $self->res->headers->add('Access-Control-Allow-Origin' => '*');

  # required for IE
  $self->write(" " x 2048);
  $self->write("\nretry: 2000\n\n");

  my $drain_cb;
  $drain_cb = sub {
    my $c = shift;
    $c->render_later;
    $c->tx($saved_tx);
    $c->pg_listen('foo', sub {
      my $notify = shift;
      my $payload = $notify->{payload};
      $c->write("id:1\ndata:$payload\n\n", $drain_cb);
    });
  };

  $self->pg_listen('foo', sub {
    my $notify = shift;
    my $payload = $notify->{payload};
    $self->tx($saved_tx);
    $self->write("id:1\ndata:$payload\n\n", $drain_cb);
  });

};

app->start;

正如你所看到的,我需要做一些hackery来让它按照我的意愿工作。 pg_listen似乎每次通话后都未定义回调。当我pg_listen再次调用时,这导致了一个错误(因为它未定义),我不得不修改PgAsync::Db.pm的第 34 行来添加一个检查:

$self->callback->($notify_hash, $notify_hash);

->到->

$self->callback->($notify_hash, $notify_hash) if defined $self->callback

前端

我正在使用带有EventSource对象的 JavaScript 来监听来自 Mojolicious 脚本的推送通知:

var es = new EventSource("/api/listen");
var listener = function (event) {
  console.log(event.data);
};
es.addEventListener("open", listener);
es.addEventListener("message", listener);
es.addEventListener("error", listener);

问题

仔细观察,这个系统似乎在不断地创建更多的数据库连接:

  1. 从无到有,有1个数据库连接,这是我在看有多少个数据库连接select count(*) from pg_stat_activity;

  2. 我开始 morbo 和 Mojolicious 脚本与DEBUG_PG=1 morbo mojopush.pl. 现在有2个数据库连接(第一个是我在psql,第二个是morbo)

  3. 我用 EventSource 对象打开网页。它使用内容类型正确设置GET请求text/event-stream并保持连接打开。现在有 3 个数据库连接

  4. 我进入 psql 并发送NOTIFY foo, 'test',Mojo 脚本检测到它,网页显示“test.txt”。仍然有 3 个数据库连接。

  5. 我刷新页面,现在有 4 个数据库连接。我等待 300 秒不活动超时,然后创建另一个数据库连接,导致 5 个连接。

如果有人可以帮助我指出正确的方向,那将不胜感激!

4

2 回答 2

1

我知道这是迟到的答案,但我和 Mojolicious 在一起的时间不超过两周。这个问题似乎没有解决,我可能会分享一些关于 PgAsync 的观察。

在使用 PgAsync 进行一些练习后,我在谷歌上搜索时发现了这篇文章。我还可以观察到“连接泄漏”,不是使用监听/通知案例,而是使用“pg”帮助程序执行一系列独立查询,在类似于此处给出的场景:https://groups。 google.com/forum/#!topic/mojolicious/titaWRImLt0

特别是,当同时发出多个请求时,就会发生泄漏。同时,我可以看到两个同时连续运行的请求循环中的一些请求,留下了未完成的查询执行和超时。

仍然没有从插件机制中了解太多,通常是 Mojo:: 事件处理,我猜可能刚刚释放的数据库连接可能太快被选择用于另一个请求。

因此,在进行了一些或多或少的盲目黑客攻击之后,我试图在数据库连接完成其请求和返回空闲池之间引入一个愚蠢的延迟。我通过更改这行代码来做到这一点:

https://metacpan.org/source/ROMANENKO/Mojolicious-Plugin-PgAsync-0.03/lib/Mojolicious/Plugin/PgAsync/Db.pm#L49

至:

$reactor->timer(1 => sub { $self->make_free->($self) });

在那之后,连接泄漏和不完整的请求都消失了。这绝对不是修复,而是一种解决方法。也许这也适用于您的情况。

但是,我可以看到在执行查询时客户端断开连接 ( Ctrl+ )的情况下仍然存在连接泄漏。C这种情况会使数据库连接在 db_pool 处“孤立”,并且永远不会返回到 db_free。

除非作者更快地得到它,否则我希望更深入地研究插件的代码,找到真正的修复,并可能添加一些增强功能。在我目前的工作中,我非常需要这个插件。

于 2014-01-07T11:35:10.020 回答
1

不是 100% 肯定,所以根据提供的信息,这有点猜测,但我想知道每个页面加载是否正在启动一个新的数据库连接,然后该连接正在侦听通知。如果是这种情况,我想知道数据库连接是否有效地从池中删除,因此在下一页加载时创建。

如果是这种情况,我的建议是有一个单独的 DBI 数据库句柄专门用于侦听通知,以便这些在队列中不活动。这可能在您的页面工作流程之外完成。

于 2013-12-20T09:09:33.143 回答