-->

Perl的FCGI退出而不Dieing(Perl FCGI Exit Without Dieing)

2019-10-30 10:20发布

如何结束脚本,如果不使用Perl FCGI使用退出使用。 寻找几天后,我发现的唯一的解决办法是在标签的主要脚本跳。 下面是主要的index.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模块内停止程序的执行。 当然,我不能用退出,因为它会终止FCGI过程中,我尝试了所有的错误,并抛出并尝试模块全部采用模具也结束处理。 当然,我可以使用从各子返回但这将需要改写为FCGI整个程序。

Answer 1:

在Perl异常模型中的正常的方法是调用dieeval BLOCK ,其中捕获die ,因此不会终止进程。 它只会终止eval ,程序继续从随后立即运行。 据我所看到的,在CPAN异常处理模块主要是围绕这一基本功能的包装给它不同的语法或使其更容易编写catch块。 因此,我很惊讶,这些不为你工作。 你真的尝试一下,还是你只是假设die总是杀死进程? 这个名字有些误导,因为它确实意味着“抛出一个异常”。 只是如果你这样做外部eval解释捕获它,它的唯一的反应是终止进程。

eval {
  say "Hello world";
  die;
  say "Not printed";
};
say "Is printed";

你不想叫exit内的eval虽然。 没有抓住这一点。

我会建议虽然重写FCGI整个控制流程。 你的代码的生命周期显著的变化,所以你必须做出修改一定量,以确保该变量的再利用工作正常,你不会泄漏内存。 通常,这是更好地做在前面,而不是花几天的跟踪奇怪的错误后。



Answer 2:

几个问题,深入的研究后,我得到了这个解决方案。 该编码例允许你从电话中的任何嵌套水平恢复。 该模块范围::上是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;


文章来源: Perl FCGI Exit Without Dieing
标签: perl fastcgi