http://www.perlmonks.org?node_id=1110800

BroFish has asked for the wisdom of the Perl Monks concerning the following question:

Hello all.

I am building a web app that will run compliance checks on client-submitted files placed in a special directory. These checks can run for more than a minute, and I want the output from those checks to be displayed in the web browser as they are generated...not waiting to the end of the run. The non-blocking Mojolicious server and WebSockets seem like a good solution technique.

In the following code, &myapp() simulates the long running checks, occasionally producing output. The good news is the desired output appears in the web browser, that output being "Connection open. Entering log4. Entering myapp. 0... 1... 2... 3... Leaving myapp. Leaving log4." The problem is the web browser sits idle for 12 seconds, and then the output displays all at once. Instead, I would like the output to appear in the web browser as soon as $tx->send() is called. How can that be accomplished with Mojolicious?

Tcpdump shows the web server is sending the output all at once, not as $tx->send() is called.

Here is the complete, running code (in one file):

#!/usr/bin/perl ## run as: ./wbsckt.pl daemon use Mojolicious::Lite; ## Automatically enables "strict", "warnings", "utf8" and Perl 5.10 fe +atures; &startup; ##------------------------------------------------------------------- sub myapp{ my $tx=shift; $tx->send("Entering myapp."); foreach my $xx (0..3) { $tx->send("$xx..."); sleep(3); } $tx->send("Leaving myapp."); return "You should never see this."; } ##------------------------------------------------------------------- sub startup{ get '/' => sub { my $c=shift; $c->render('index'); }; get '/log2' => sub { my $c=shift; $c->render('log2'); }; websocket '/log3' => \&ws_log4; app->secrets(['password' => '8675309J']); app->start; } ##------------------------------------------------------------------- sub ws_log4{ my $self= shift; my $tx= $self->tx; my $ip= $tx->remote_address; app->log->debug("Client '$ip' connected"); $tx->send("Entering log4."); $self->on(&myapp($tx) => sub { my($ws,$msg)= @_; $ws->inactivity_timeout(50); $ws->send("Time is: " . scalar(localtime())); ## odd, we neve +r see this output }); $self->on(finish => sub { my($c,$code,$reason)= @_; $c->app->log->debug("WebSocket closed with status $code."); }); $tx->send("Leaving log4."); } ##------------------------------------------------------------------- __DATA__ @@ index.html.ep <!DOCTYPE html> <html> <head><title>Static Page</title> </head> <body> <h1>Index Page</h1> <p>This is a static page. For WebSockets example, click <a href="/log2">here</a>. </p> </body> </html> @@ log2.html.ep <!DOCTYPE html> <html> <head> <title>WebSockets Example</title> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min. +js"></script> </head> <body> <p id="result"></p> %= javascript begin var ws = new WebSocket('<%= url_for('log3')->to_abs %>'); ws.onopen = function() { $('#result').text("Connection open."); //ws.send("Hi."); }; ws.onmessage = function (e) { $('#result').append( "\n" + e.data); }; % end </body> </html>

This code is running on CentOS 6.5, Perl 5.10.1 with these perl modules: EV 4.18; IO::Socket::Sockets 0.65; IO::Socket::SSL 2.007.

Thank you very much for your insight and patience.