Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked

cgi,wait for long running external prog

by noname (Sexton)
on Feb 13, 2014 at 18:29 UTC ( #1074871=perlquestion: print w/replies, xml ) Need Help??
noname has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,
I am looking for a kind advise for the following problem:
I need to run an external command which can take long time to run ( minutes or even hours ) I use for that Proc::Background.
Now I need a way to tell the browser to refresh the page until the result is ready, Or implement a way to check that process is still running.
That's what I managed to do for now and to be honest it looks very ugly:
It doesn't matter in general but I use perl dancer for my little web project.

any '/run' => sub { my $dest = '/var/local/testp/public/results'; my ($fh,$filename) = tempfile(); my $command = "/usr/bin/R -q --slave --vanilla < /var/local/te +stp/data/code.R > $filename && mv $filename $dest/${filename}\.html"; my $proc1 = Proc::Background->new($command); my $htmlfile = "$dest" . "$filename" . '.html'; open (my $hfh,">>",$htmlfile) or die "can\'t open file $htmlfi +le: $!\n"; print $hfh "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"5; URL=/res +ults/${filename}\.html\">"; print $hfh "waiting for \<a href=\"/results/${filename}\.html\ +"> results</a>"; close $hfh; unlink ($fh); return redirect "/results/${filename}\.html"; };
so basically I create an empty static html page which refreshes itself each 5 seconds
and when the process is finished I simply overwrite the this page with the result.
it works, but I think there is a better and more elegant way to do it.

Thank you.

Replies are listed 'Best First'.
Re: cgi,wait for long running external prog
by bpmedley (Initiate) on Feb 13, 2014 at 22:45 UTC

    This is a Mojolicious::Lite answer and has been tested in Windows and OS X:

    use Mojolicious::Lite; use File::Temp qw(tempfile); use Proc::Background; use Fcntl qw(SEEK_SET); use IO::Handle; any '/run' => sub { my $self = shift; my ($fh,$filename) = tempfile(); my $script; my $tmp = File::Temp->new( UNLINK => 0, SUFFIX => '.pl'); say($tmp "#!perl\n", "\n", "use IO::Handle;\n", q(open($fh, ">", $ARGV[0]);), "\n", q($fh->autoflush(1);), "\n", q(do { print($fh scalar(localtime), "\n"); sleep 1 } forea +ch (1 .. 20);), "\n", ); $script = $tmp->filename; undef($tmp); $self->app->log->debug("script: $script"); my $command = qq($^X $script $filename); $self->app->log->debug("Command: $command"); my $proc = Proc::Background->new($command); Mojo::IOLoop->stream($self->tx->connection)->timeout(30); $self->render_later; my $recurring = Mojo::IOLoop->recurring(1 => sub { my $tmp_fh = $self->stash->{_fh}; my $told = $self->stash->{_told} // 0; my $proc = $self->stash->{_proc}; $self->app->log->debug("Recurring: " . $proc->pid); my $file = $self->stash->{_filename}; open(my $fh, "<", $file); if (fileno($fh)) { seek($fh, $told, SEEK_SET); read($fh, my $buf, 1024); $self->stash->{_told} = tell($fh); chomp($buf); $self->write_chunk(qq(<script>document.getElementB +yId("stuff").innerHTML += "$buf<br>";</script>\n)); } if ($proc->alive) { return; } $self->app->log->debug("Done"); $self->write_chunk("Done</body></html>"); $self->finish; }); $self->stash->{_recurring} = $recurring; $self->stash->{_fh} = $fh; $self->stash->{_filename} = $filename; $self->stash->{_proc} = $proc; $self->on(finish => sub { my $fh = $self->stash->{_fh}; my $recurring = $self->stash->{_recurring}; Mojo::IOLoop->remove($fh); Mojo::IOLoop->remove($recurring); $self->app->log->debug("Finished"); }); $self->res->code(200); $self->res->headers->content_type('text/html'); $self->write_chunk("<html><body><div id=stuff>Starting...<br>< +/div>"); }; push(@ARGV, 'daemon', '-l', 'http://*:5555') unless @ARGV; app->log->level("debug"); app->secrets(["I Knos# you!!"]); app->start;
      Cool! thanks for posting, it is definitely useful for Mojo adepts :)
      But I am looking for a simpler solution and currently don't have time to dive in a new framework.

      Hi I'm interesting in your posted example, and if you can please specify more clearly how to use the code for call a system perl classical script. Thanks

Re: cgi,wait for long running external prog
by kschwab (Priest) on Feb 13, 2014 at 18:50 UTC

    The most user friendly set up would probably be for you to maintain a list of currently running jobs and their state (running, aborted, completed). Then, either a manual refresh button, or if you really need auto-refresh, do it with ajax so that the whole page isn't reloading.

    There's a dancer-oriented example that's pretty close to what you're looking for here:

    This one is chart oriented, but the same idea at a high level.

      Thank you, looks interesting. I'll post an update if I manage to implement it this way.
Re: cgi,wait for long running external prog
by sundialsvc4 (Abbot) on Feb 14, 2014 at 02:18 UTC

    Two thoughts here ...

    First of all, in this case you should think of “a web page” as merely being a form of user-interface.   The fundamental nature of this user interface is that it appears, it exists, and then (forever ...) it is gone.   The user does not want to wait until his request is actually completed; nor should he have to; nor does the HTTP protocol support it.   Therefore, if you have long-running work to do, you need a separate mechanism, entirely apart from any and every web-page, entirely apart from the Apache-or-whatever web-server, to do that.

    Second, “batch-job managers” already exist for every computing platform.   So do (web, and other) interfaces to them.   Therefore, your present requirement does not consist of “rolling your own [anything].”   It consists of finding, and employing, prior-art.   You are in Rome.   Find some Romans, and go do what they are [already ...] doing.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1074871]
Approved by GotToBTru
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (2)
As of 2018-05-21 22:44 GMT
Find Nodes?
    Voting Booth?