2
votes

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?

1
all the code on your web server can be divided into two parts: servicing the response and related work. usually having queue service for related work is the best solution. so... why you don't want to add a queue?T'East
you can use hooks, after sending response you can do your background process in another hook by simply calling next() in your function.Suresh Shetiar
The event hook is optional in Plack because the base implementation must be abstract enough to run on many types of servers. Use Plack::Handler::Net::Async::HTTP::Server to expose $env->{'io.async.loop'}, for example.daxim

1 Answers

2
votes

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]];
};