简体   繁体   English

Perl警报无法正常工作

[英]perl alarms not working as expected

I have a simple perl script that calls a shell script which always "hangs" when called from the browser. 我有一个简单的perl脚本,该脚本调用一个shell脚本,当从浏览器中调用该脚本时,该脚本始终“挂起”。 I want to simply force a time out after 20 seconds. 我只想在20秒后强制超时。 When I run it in command line there is no issues. 当我在命令行中运行它时,没有问题。 But when I do it from the browser, the script is executed but never finishes loading. 但是,当我从浏览器中执行该脚本时,该脚本已执行但从未完成加载。 So I don't get the output on the page. 所以我在页面上没有得到输出。 If I kill -9 the process in the command line, the browser finishes loading, and the content is displayed in the browser. 如果我在命令行中杀死-9,则浏览器将完成加载,并且内容将显示在浏览器中。

I did a lot of research, and it seems the web server is waiting for the shell script to finish, because the shell script still has an open file handle to the standard output. 我做了很多研究,似乎Web服务器正在等待Shell脚本完成,因为Shell脚本仍具有标准输出的打开文件句柄。

Here is my code. 这是我的代码。

#!/usr/bin/perl

use strict;
use warnings;

use CGI;

my $q = new CGI;

print $q->header;

my $timeout = 10;
my $pid = fork;

if ( defined $pid ) {
     if ( $pid ) {

         # this is the parent process
         local $SIG{ALRM} = sub { die "TIMEOUT" };

         alarm 10;

         # wait until child returns or timeout occurs    
         eval {
             waitpid( $pid, 0 );
         };

         alarm 0;

         if ( $@ && $@ =~ m/TIMEOUT/ ) {
            # timeout, kill the child process
            kill 9, $pid;
         }
    }
    else {
         # this is the child process
         # this call will never return. Note the use of exec instead of system
         exec "/opt/bea/domains/fsa/scripts/start.sh";
    }
}
else {
     die "Could not fork.";
}

How do I force the page to finish loading regardless of the status of the shell script after a certain amount of time. 在一定时间后,无论外壳脚本的状态如何,如何强制页面完成加载。

Problem is that after your script finishes, webserver is still waiting for all child created (even created by you) to finish. 问题在于脚本完成后,Web服务器仍在等待所有创建的子级(甚至由您创建的子级)完成。 Best way how to handle it is to create separate process group with setsid . 最好的处理方法是使用setsid创建单独的进程组。 Or you can even try the " double fork trick ", where you fork and from child then fork again. 或者,您甚至可以尝试“ 双叉把戏 ”,在该叉上从孩子处分叉,然后再次分叉。 After that the first child will exit and the second child becomes child if init . 此后,第一个孩子将退出,而第二个孩子将通过init成为孩子。 Also make sure that (in both cases) in child you do: 还要确保(在两种情况下)在孩子中都可以做到:

close STDIN;
close STDOUT;
close STDERR;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM