Aaron
Aaron

Reputation: 462

How do I write a Plack middleware that runs after the HTTP response is sent to the client?

My Plack web service logs via a TCP connection to fluentD, and I'd like to execute my logging code after I've sent the response back to the client. This would reduce response time (assume this is a high request volume service where such a performance optimization is worth doing).

At least one other web framework, express for nodejs, supports this by enabling middlewares to add an on-end event handler to the request object. I've looked at the Plack::Request and Plack::Response interfaces, and I didn't see a similar event hook.

I think I could probably do a local override of the finalize method in my middleware to force the framework to do my logging after the response is finalized, but I'd like to avoid tinkering with the Plack internals if possible.

Is there a better way to defer execution of some code until after a response has been sent to the client?

Upvotes: 2

Views: 392

Answers (1)

daxim
daxim

Reputation: 39158

Thanks to LeoNerd and ilmari for their debugging help in 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]];
};

Upvotes: 2

Related Questions