简体   繁体   English

如何使用Perl FCGI杀死我?

[英]How do I get killed using Perl FCGI?

I'm having a little problem with nginx and the Perl FCGI module. 我在使用nginx和Perl FCGI模块时遇到了一些问题。 I have a long operation in my FCGI program that may outlive the server (or the user on the server) on the other end of the Unix socket I'm using to communicate FCGI. 我在FCGI程序中进行的操作很长,可能使服务器(或服务器上的用户)的寿命超出了我正在用于通信FCGI的Unix套接字另一端的时间。 I need the FCGI accept() loop in my program to break if the FCGI request is closed. 如果FCGI请求已关闭,我需要程序中的FCGI accept()循环中断。 I tried installing INT, TERM, etc signal handlers, but they do nothing, since the only communication between nginx and my program happens over the FCGI socket, AFAIK. 我尝试安装INT,TERM等信号处理程序,但是它们什么也没做,因为nginx和我的程序之间的唯一通信是通过FCGI套接字AFAIK进行的。

I also tried this but there's no way that I can see to use the FCGI module in Perl to send raw data to or from nginx over the FCGI socket. 我也尝试过这种方法,但是无法看到在Perl中使用FCGI模块通过FCGI套接字向nginx发送原始数据或从nginx发送原始数据。 Is there a way I can do it without modifying the FCGI module to have a "ping" function? 有没有一种方法可以修改FCGI模块以使其具有“ ping”功能?

The basic problem is that my program does not know if nginx has terminated the FCGI request. 基本问题是我的程序不知道nginx是否已终止FCGI请求。

Example: 例:

#!/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;
}

You have to use a FCGI implementation which treats FCGI_ABORT_REQUEST . 您必须使用处理FCGI_ABORT_REQUESTFCGI实现。

You cannot use the following, because they ignore FCGI_ABORT_REQUEST : 不能使用以下内容,因为它们会忽略FCGI_ABORT_REQUEST

You could use the following, which treat FCGI_ABORT_REQUEST : 可以使用以下代码来对待FCGI_ABORT_REQUEST

When using AnyEvent-FCGI , checking for an aborted request is as easy as calling $request->is_active() , but keep in mind that is_active() will not reflect the true state of the request until the on_request handler returns, which means you have to return from on_request as soon as possible and somehow do the actual work "in parallel" (you probably don't want to use Perl threads , but something more akin to continuations ) in order to give the AnyEvent loop the opportunity to process any further requests (including FCGI_ABORT_REQUEST s) while you are completing the long-winded operations. 使用AnyEvent-FCGI ,检查中止的请求就像调用$request->is_active()一样容易,但是请记住,在on_request处理程序返回之前, is_active()不会反映请求的真实状态,这意味着您必须尽快从on_request返回,并以某种方式“并行”执行实际工作(您可能不想使用Perl线程 ,但更类似于延续 ),以便使AnyEvent循环有机会处理任何在完成冗长的操作时,还会有其他请求(包括FCGI_ABORT_REQUEST )。

I am not familiar enough with AnyEvent to know for sure whether there is a better way of doing this, but here's my take, below, for a start: 我对AnyEvent不够熟悉, 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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM