【问题标题】:How do I write a Plack middleware that runs after the HTTP response is sent to the client?如何编写在 HTTP 响应发送到客户端后运行的 Plack 中间件?
【发布时间】:2020-02-24 13:25:03
【问题描述】:

我的 Plack Web 服务通过与 fluentD 的 TCP 连接进行日志记录,并且我想在将响应发送回客户端后执行我的日志记录代码。这将减少响应时间(假设这是一个高请求量服务,值得进行这种性能优化)。

至少有一个其他的 web 框架,用于 nodejs,通过启用中间件添加 on-end event handler to the request object 来支持这一点。 我查看了Plack::RequestPlack::Response 接口,但没有看到类似的事件挂钩。

我想我可能会在我的中间件中对 finalize 方法进行本地覆盖,以强制框架在响应完成后进行日志记录,但如果可能的话,我想避免修改 Plack 内部结构。

有没有更好的方法可以将某些代码的执行推迟到向客户端发送响应之后?

【问题讨论】:

  • 您网络服务器上的所有代码都可以分为两部分:服务响应和相关工作。通常为相关工作提供队列服务是最好的解决方案。所以...为什么你不想添加队列?
  • 您可以使用钩子,在发送响应后,您可以通过在函数中调用 next() 在另一个钩子中执行后台进程。
  • 事件挂钩在 Plack 中是可选的,因为基本实现必须足够抽象才能在多种类型的服务器上运行。例如,使用Plack::Handler::Net::Async::HTTP::Server 公开$env->{'io.async.loop'}

标签: perl asynchronous middleware deferred-execution plack


【解决方案1】:

感谢 LeoNerd 和 ilmari 在 MagNET #io-async 中提供的调试帮助。

#!/usr/bin/env -S plackup -s Net::Async::HTTP::Server
use Future::AsyncAwait;
use Time::HiRes qw(time);
use Future::IO qw();
use Future::IO::Impl::IOAsync qw();

async sub mylogger {
    # simulate expensive run-time
    await Future::IO->sleep(1);
    open my $log, '>>', '/tmp/so-58605156.log';
    $log->say(time);
}

my $app = sub {
    my ($env) = @_;
    mylogger->retain;
    return [200, ['Content-Type' => 'text/plain'], [time]];
};

【讨论】:

  • 我看到你正在运行一个 Net::Async::HTTP::Server 服务器。在 Starman 这样的 pre-fork 服务器中是否无法进行日志记录后响应?
  • 更多可能性: 1. 使用一个简单的进程分叉和管道日志到其中,例如Proc::Fork。 2、将logger代码放入外部logger程序中;在需要时将其作为后台进程生成。 3. 使用作业队列,例如Minion.
猜你喜欢
  • 2013-07-19
  • 2011-05-17
  • 2020-09-04
  • 1970-01-01
  • 1970-01-01
  • 2017-05-29
  • 2015-09-24
  • 1970-01-01
  • 2014-09-13
相关资源
最近更新 更多