如果使用Perl FCGI,如何在不使用exit的情况下结束脚本。搜索了几天后,我发现的唯一解决方案是跳转到主脚本中的标签。下面是主索引的代码.fcgi。
$fcgi_requests = 0; # the number of requests this fcgi process handled.
$handling_request = 0;
$exit_requested = 0;
$app_quit_request = 0; # End the application but not the FCGI process
# workaround for known bug in libfcgi
while (($ignore) = each %ENV) { }
$fcgi_request = FCGI::Request();
#$fcgi_request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket);
sub sig_handler {
my ($callpackage, $callfile, $callline) = caller;
if ($app_quit_request) {
$app_quit_request = 0;
goto ABORTLABEL;
}
$exit_requested = 1;
exit(0) if !$handling_request;
}
$SIG{USR1} = \&sig_handler;
$SIG{TERM} = \&sig_handler;
$SIG{PIPE} = 'IGNORE';
#The goal of fast cgi is to load the program once, and iterate in a loop for every request.
while ($handling_request = ($fcgi_request->Accept() >= 0)) {
process_fcgi_request();
$handling_request = 0;
last if $exit_requested;
#exit if -M $ENV{SCRIPT_FILENAME} < 0; # Autorestart
}
$fcgi_request->Finish();
exit(0);
#=========================================================#
sub process_fcgi_request() {
$fcgi_requests++;
# dispatch current request
my_app();
$fcgi_request->Finish();
}
#=========================================================#
# let it think we are done, used by abort
ABORTLABEL:
$fcgi_request->Finish();
#=========================================================#
主要请求是我想从子insidi模块内部停止程序执行,这些模块可能被深度调用,例如在帐户模块中的登录功能中。 当然我不能使用exit因为它将终止fcgi进程,我尝试了所有错误并抛出并尝试模块所有使用die也结束了进程。当然我可以使用每个sub的返回但这需要重写fcgi的整个程序。
答案 0 :(得分:1)
在Perl中建模异常的常规方法是在die
内调用eval BLOCK
,这会捕获die
,因此不会终止进程。它只会终止eval
,程序会立即继续运行。据我所知,CPAN上的异常处理模块主要是围绕这个基本功能的包装器,为它提供不同的语法或者更容易编写catch块。所以我很惊讶这些不适合你。你真的试过它们还是只是假设die
总是杀了这个过程?这个名字有点误导,因为它的确意味着“抛出异常”。如果你在eval
以外的地方做到这一点,那么解释器会抓住它,而它唯一的反应是终止这个过程。
eval {
say "Hello world";
die;
say "Not printed";
};
say "Is printed";
您不想在exit
内拨打eval
。什么都没有。
我建议尽管重写FCGI的整个控制流程。代码的生命周期发生了显着变化,因此您必须进行一定数量的修改,以确保变量重用正常并且您不会泄漏内存。通常最好事先做好,而不是花几天时间追踪奇怪的错误。
答案 1 :(得分:0)
经过几个问题和深入研究,我得到了这个解决方案。此编码示例允许您从任何嵌套级别的调用返回。模块Scope::Upper是XS,所以它应该很快。
use Scope::Upper qw/unwind CALLER/;
sub level1 {
print "before level 1 \n";
level2();
print "after level 1 \n";
}
sub level2 {
print "before level 2 \n";
level3();
print "after level 2 \n";
}
sub level3 {
print "before level 3 \n";
level4();
print "after level 3 \n";
}
sub level4 {
print "before level 4 \n";
#unwind CALLER 2;
my @frame;
my $i;
#$i++ while @frame = caller($i);# and $frame[0] ne "main";
$i++ while @frame = caller($i);
#print "i=: $i \n";
#unwind CALLER (@frame ? $i : $i - 1);
unwind CALLER $i-1;
print "after level 4 \n";
}
print level1();
如果您运行此代码,则输出将为:
before level 1
before level 2
before level 3
before level 4
您可以使用以下方式返回任何更高级别:
my intLevel = 2;
unwind CALLER intLevel;