代码之家  ›  专栏  ›  技术社区  ›  njahnke

如何使用perl fcgi杀死我?

  •  8
  • njahnke  · 技术社区  · 16 年前

    我对nginx和perl fcgi模块有点问题。我的fcgi程序中有一个很长的操作,可能比我用来通信fcgi的unix套接字的另一端的服务器(或服务器上的用户)长。如果fcgi请求关闭,我需要程序中的fcgi accept()循环中断。我尝试安装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 回复  |  直到 14 年前
        1
  •  1
  •   Tim Cooper    14 年前

    你必须使用 FCGI 实施 对待 FCGI_ABORT_REQUEST .

    不能 使用以下内容,因为它们忽略了 fcgi_中止请求 :

    可以使用 以下内容: 对待 fcgi_中止请求 :

    使用时 AnyEvent-FCGI ,检查中止的请求与调用一样简单。 $request->is_active() 但请记住 is_active() on_request 处理程序返回,这意味着您必须从返回 单请求 尽快并且以某种方式“并行”完成实际工作(您可能不想使用 Perl threads 但更类似于 continuations )为了给 AnyEvent 循环处理任何进一步请求的机会(包括 fcgi_中止请求 s)当您完成长距离操作时。

    我不太熟悉 任何事件 为了确定是否有更好的方法可以做到这一点,下面是我的看法,首先:

    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;