Re: cleanup a cancelled CGI script
by sgifford (Prior) on Jun 08, 2004 at 19:00 UTC
|
IIRC, the script doesn't actually die when the user hits STOP on their Web browser; I'm not aware of any mechanism to inform the script of this. Instead, when the script tries to send data back to the user, it sees that the socket has been closed, and receives a SIGPIPE. I believe that installing a signal handler for this signal will allow you to detect when this has happened:
$SIG{PIPE} = sub { die "Connection closed while processing!\n" }
| [reply] [d/l] [select] |
|
eval {
do_stuff( ... );
1;
} or cleanup( ... )
| [reply] [d/l] |
Re: cleanup a cancelled CGI script
by iburrell (Chaplain) on Jun 08, 2004 at 19:12 UTC
|
On Unix, the CGI script is attached to the web server through a pipe or socket. A write to a closed pipe or socket produces a SIGPIP signale that by default kills your program. It is possible to safely cleanup by adding a signale handler.
$SIG{PIPE} = sub { die "Pipe error"; }
By turning the signal into a die, the error is logged and END blocks will be run.
| [reply] [d/l] |
Re: cleanup a cancelled CGI script
by saskaqueer (Friar) on Jun 08, 2004 at 19:32 UTC
|
I tried the solution of using SIGPIPE posted by others above on Windows XP just to try it. Of course, there is no SIGPIPE sent to the script when running under Win32 (well, WinXP anyhow). What happened in my test is that the script doesn't even realize that the client has disconnected. The script finishes running normally, with no change in execution (in a simple test anyhow). Even adding a or die("print failed: $!"); to a print statement that should fail doesn't change anything. My test script below:
#!perl -w
$| = 1;
BEGIN {
$SIG{PIPE} = sub { die "Pipe error: @_\n" };
}
use strict;
use CGI;
my $q = CGI->new();
print $q->header();
print "output #1\n";
sleep 15;
# we stop the browser load during the 15 sec. sleep
print "output #2\n" or die("print failed: $!");
END {
open my $fh, '>>', 'debug.txt';
print $fh "We made it to the END block.\n";
close $fh;
}
| [reply] [d/l] [select] |
|
I think (on Windows, anyway) that you'd have to have a sweeper (reaper?) process that comes along every hour or so looking for ZIP files that are older than, say, one hour, and assume that they are incomplete, and delete them.
Or you could add them to a database, or send them to another process, whose job it is delete any ZIPs in its list (or database) that are older than x hours.
| [reply] |
|
Why not just do it in the script when it runs?
my $tmp_dir = "/path/to/tmpdir";
opendir(TMPDIR,$tmp_dir) || die $!;
-M "$tmp_dir/$_" > 1/24 and unlink "$tmp_dir/$_" for (grep /zip/, read
+dir(TMPDIR));
closedir(TMPDIR);
or similar (untested).
cLive ;-) | [reply] [d/l] |
|
|
|
++ That's what I would've recommeneded. (Or, similarly, use one of the Win32::Process and on startup, put pid into database, then when pid dies, have a second process kill the pid related to the .zip file...)
| [reply] |
|
| [reply] |
|
| [reply] [d/l] |
Re: cleanup a cancelled CGI script
by goofball (Acolyte) on Jun 08, 2004 at 20:40 UTC
|
I'm running the script on a Unix-based FreeBSD system running the Apache 1.3.27 server.
I think I'll use the SIGPIPE approach.
There are already a lot of crons on my server - and the thing about those is I get an email from the root process every time one runs. I think it's more elegant to have the script clean up after itself.
And thanks to saskaqueer for your post. I didn't even think to use an "or die" statement on a print call. Not enough coffee today ...
Thanks! You monks are awesome.
| [reply] |
|
As an aside, if the only thing you don't like about cron is that it emails you the output from the programs it runs, you can stop that by redirecting a program's output to /dev/null like this:
... your_script >/dev/null 2>&1
| [reply] [d/l] |
Re: cleanup a cancelled CGI script
by jayrom (Pilgrim) on Jun 08, 2004 at 20:47 UTC
|
This will probably not apply directly to your problem as it refers to mod_perl but it is an interesting read nonetheless.
jayrom | [reply] |
Re: cleanup a cancelled CGI script
by cLive ;-) (Prior) on Jun 08, 2004 at 21:15 UTC
|
I may be missing something, but is there anything wrong with fork?
#!/usr/bin/perl
use strict;
use warnings;
use POSIX ":sys_wait_h";
$|++;
print "Content-type:text/plain\n\nStarting script.....\n\n";
my $pid;
if (!defined($pid = fork)) {
die "Could not fork! $!";
}
elsif ($pid) {
# parent - clean up when child exits
1 while (waitpid($pid,WNOHANG) != -1);
cleanup();
exit(0);
}
else {
# child - does the processing
print "Processing...\n\n";
sleep(5);
print "Finished...\n\n";
exit(0);
}
sub cleanup {
# do the clean up here
}
In my test CGI $|++ doesn't seem to do anything. I can't work out why the output appears buffered - is that a fork side effect?
cLive ;-) | [reply] [d/l] |
Re: cleanup a cancelled CGI script
by Anonymous Monk on Jun 08, 2004 at 21:14 UTC
|
try using the sigtrap module | [reply] |
|
UPDATE::
I got a lot of good advice after posting this thread - thanks to all.
I tried using
$SIG{PIPE} = sub { ... };
but found that it wasn't working all the time. It turns out that by hitting the stop button on the browser, a SIGTERM was ending the script in stead.
I took this anonymous suggestion to use the sigtrap module, and that's working flawlessly now. Thanks!
use sigtrap qw(die untrapped normal-signals);
END { ... here's where I clean up the zip file ... }
sigtrap | [reply] [d/l] [select] |