8

我对 nginx 和 Perl FCGI 模块有一点问题。我在我的 FCGI 程序中有一个很长的操作,它可能比我用来通信 FCGI 的 Unix 套接字另一端的服务器(或服务器上的用户)寿命更长。如果 FCGI 请求关闭,我需要在我的程序中使用 FCGI accept() 循环来中断。我尝试安装 INT、TERM 等信号处理程序,但它们什么也没做,因为 nginx 和我的程序之间的唯一通信是通过 FCGI 套接字 AFAIK 进行的。

我也试过这个,但是我看不到使用 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;
}
4

1 回答 1

1

您必须FCGI使用处理FCGI_ABORT_REQUEST.

不能使用以下内容,因为它们会忽略FCGI_ABORT_REQUEST

可以使用以下内容,其中处理FCGI_ABORT_REQUEST

使用时AnyEvent-FCGI,检查中止请求就像调用一样简单$request->is_active(),但请记住,is_active()在处理程序返回之前,它不会反映请求的真实状态on_request,这意味着您必须尽快返回on_request并以某种方式完成实际工作“并行”(您可能不想使用Perl 线程,但更类似于continuations的东西),以便在您完成冗长的操作时让AnyEvent循环有机会处理任何进一步的请求(包括s)。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;
于 2010-03-09T01:37:58.263 回答