RTF
RTF

Reputation: 6494

End perl script without waiting for system call to return

I'm running a simple apache web server on Linux (Ubuntu 14.04) with a perl CGI script handling some requests. The script initiates a system command using the system function, but I want it to return immediately, regardless of the outcome of the system call.

I've been adding an ampersand to the end of the scalar argument passed to system (I am aware of the implications of command injection attacks) and although this does cause the system command to return immediately, the script will still not exit until the underlying command has completed.

If I trigger a dummy ruby script with a 10 second sleep using the system call from the perl CGI, then my request to the web server still waits 10 seconds before finally getting a response. I put a log statement after the system call and it appears immediately when the web request is made, so the system call is definitely returning immediately, but the script is still waiting at the end.

This question is similar, but neither of the solutions have worked for me.

Here's some example code:

#!/usr/bin/perl
use strict;
use warnings;
use CGI;
use Log::Log4perl qw(:easy);

Log::Log4perl->easy_init(
    { level => $DEBUG, file => ">>/var/log/script.log" } );

print "Content-type: application/json\n\n";
my $cgi = CGI->new();

INFO("Executing command...");
system('sudo -u on-behalf-of-user /tmp/test.rb one two &');
INFO("Command initiated - will return now...");

print '{"error":false}';

Edit:
The command call is executed using sudo -u because the apache user www-data needs permission to execute the script on behalf of the script owner, and I've updated my sudoers file appropriately to that end. This is not the cause of my issue, because I've also tried changing script ownership to www-data and running system("/tmp/test.rb one two &") but result is the same.

Edit 2:
I've also tried adding exit 0 to the very end of the script, but it doesn't make any difference. Is it possible that the script is exiting immediately, but the apache server is holding onto the response until the script the perl CGI called is finished? Or is it possible that some setting or configuration of the operating system is causing the problem?

Edit 3:
Running the perl CGI script directly from a terminal works correctly. The perl script ends immediately, so this is not an inherent issue with Perl. Which presumably can only mean that the Apache web server is holding onto the request until the command called from system is finished. Why?

Upvotes: 3

Views: 1111

Answers (1)

ikegami
ikegami

Reputation: 385655

The web server creates a pipe from which to receive the response. It waits for the the pipe to reach EOF before completing the request. A pipe reaches EOF when all copies of the writer handle are closed.

The writer end of the pipe is set as the child's STDOUT. That file handle was copied to be the shell's STDOUT, and again to the mycmd's STDOUT. So even though the CGI script and the shell ended and thus closed their ends of the file handle, mycmd still holds the handle open, so the web server is still waiting for the response to complete.

All you have to do with to close the last handle to the writer end of the pipe. Or more precisely, you can avoid making it in the first place by attaching a different handle to mycmd STDOUT.

mycmd arg1 arg2 </dev/null >/dev/null 2>&1 &

Upvotes: 4

Related Questions