سؤال

أواجه مشكلة صغيرة مع NGINX ووحدة Perl FCGI. لديّ عملية طويلة في برنامج FCGI الخاص بي قد يفوق الخادم (أو المستخدم على الخادم) على الطرف الآخر من مقبس UNIX الذي أستخدمه لتوصيل FCGI. أحتاج إلى حلقة FCGI ACCEPT () في برنامجي لكسر إذا تم إغلاق طلب FCGI. لقد حاولت تثبيت int ، المصطلح ، إلخ معالجات الإشارات ، لكنهم لا يفعلون شيئًا ، لأن التواصل الوحيد بين Nginx وبرنامجي يحدث على مقبس FCGI ، AFAIK.

لقد حاولت أيضا هذه ولكن لا توجد طريقة يمكنني من خلالها استخدام وحدة FCGI في Perl لإرسال بيانات RAW إلى NGINX أو من مقبس FCGI. هل هناك طريقة يمكنني القيام بذلك دون تعديل وحدة 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;
}
هل كانت مفيدة؟

المحلول

عليك استخدام أ FCGI التنفيذ الذي يعامل FCGI_ABORT_REQUEST.

أنت لا تستطيع استخدم ما يلي ، لأنهم يتجاهلون FCGI_ABORT_REQUEST:

أنت يمكن استخدام ما يلي ، يعالج FCGI_ABORT_REQUEST:

عند استخدام AnyEvent-FCGI, ، إن التحقق من طلب تم إحباطه أمر سهل مثل الاتصال $request->is_active(), ، لكن ضع في اعتبارك ذلك is_active() لن يعكس الحالة الحقيقية للطلب حتى on_request يعود المعالج ، مما يعني أنه يجب عليك العودة من on_request في أقرب وقت ممكن وقام بعمله الفعلي بطريقة أو بأخرى "بالتوازي" (ربما لا تريد استخدامها المواضيع بيرل, ، ولكن شيء أقرب إلى الاستمرارية) من أجل إعطاء AnyEvent حلقة الفرصة لمعالجة أي طلبات أخرى (بما في ذلك FCGI_ABORT_REQUESTS) أثناء استكمال العمليات الطويلة.

أنا لست على دراية بما يكفي 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 مع الإسناد
لا تنتمي إلى StackOverflow
scroll top