如何使用Perl FCGI杀死?

时间:2010-02-26 21:57:47

标签: perl nginx ping fastcgi

我在使用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;
}

1 个答案:

答案 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;