我在使用nginx和Perl FCGI模块时遇到了一些问题。我在我的FCGI程序中有一个很长的操作,可能比我用来与FCGI通信的Unix套接字另一端的服务器(或服务器上的用户)一样。我需要程序中的FCGI accept()循环才能在FCGI请求关闭时中断。我尝试安装INT,TERM等信号处理程序,但它们什么都不做,因为nginx和我的程序之间的唯一通信是通过FCGI套接字AFAIK进行的。
我也试过this但是我无法看到在Perl中使用FCGI模块通过FCGI套接字向nginx发送原始数据或从nginx发送原始数据。有没有办法可以在不修改FCGI模块的情况下进行“ping”功能?
基本问题是我的程序不知道nginx是否终止了FCGI请求。
示例:
#!/usr/bin/perl -w
use strict;
use FCGI;
my $fcgi_socket = FCGI::OpenSocket( '/tmp/test.socket', 100000 );
my $request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV, $fcgi_socket);
REQUEST: while($request->Accept() >= 0) {
#begin handling request
my $result = '';
while (1) { #or select(), etc
if (somehow check whether the fcgi $request is still live) {
next REQUEST;
}
#check for results, set $result if done
}
print $result;
}
答案 0 :(得分:1)
您必须使用对待FCGI
的FCGI_ABORT_REQUEST
实施。
您无法使用以下内容,因为他们会忽略FCGI_ABORT_REQUEST
:
您可以使用以下内容,对待FCGI_ABORT_REQUEST
:
使用AnyEvent-FCGI
时,检查已中止的请求就像调用$request->is_active()
一样简单,但请记住is_active()
在on_request
之前不会反映请求的真实状态1}}处理程序返回,这意味着您必须尽快从on_request
返回并以某种方式“并行”执行实际工作(您可能不想使用Perl threads,但更多类似于continuations),以便在您完成冗长的操作时为AnyEvent
循环提供处理任何进一步请求(包括FCGI_ABORT_REQUEST
)的机会。
我对AnyEvent
不太熟悉,无法确定是否有更好的方法可以做到这一点,但这是我的观点,在下面,开始:
use AnyEvent;
use AnyEvent::FCGI;
my @jobs;
my $process_jobs_watcher;
sub process_jobs {
# cancel aborted jobs
@jobs = grep {
if ($_->[0]->is_active) {
true
} else {
# perform any job cleanup
false
}
} @jobs;
# any jobs left?
if (scalar(@jobs)) {
my $job = $jobs[0];
my ( $job_request, $job_state ) = @$job;
# process another chunk of $job
# if job is done, remove (shift) from @jobs
} else {
# all jobs done; go to sleep until next job request
undef $process_jobs_watcher;
}
}
my $fcgi = new AnyEvent::FCGI(
port => 9000,
on_request => sub {
my $request = shift;
if (scalar(@jobs) < 5) { # set your own limit
# accept request and send back headers, HTTP status etc.
$request.print_stdout("Content-Type: text/plain\nStatus: 200 OK\n\n");
# This will hold your job state; can also use Continutiy
# http://continuity.tlt42.org/
my $job_state = ...;
# Enqueue job for parallel processing:
push @jobs, [ $request, $job_state ];
if (!$process_jobs_watcher) {
# If and only if AnyEvent->idle() does not work,
# use AnyEvent->timer() and renew from process_jobs
$process_jobs_watcher = AnyEvent->idle(cb => \&process_jobs);
}
} else {
# refuse request
$request.print_stdout("Content-Type: text/plain\nStatus: 503 Service Unavailable\n\nBusy!");
}
}
);
AnyEvent->loop;