2014-02-14 3 views
0

Perl FCGI를 사용하는 경우 exit를 사용하지 않고 스크립트를 종료하는 방법. 요일을 검색 한 후 내가 발견 한 유일한 해결책은 주 스크립트에서 레이블로 건너 뛰는 것입니다. 아래는 주요 index.fcgi 코드입니다.Perl FCGI 종료하지 않고 종료

$fcgi_requests = 0; # the number of requests this fcgi process handled. 
$handling_request = 0; 
$exit_requested = 0; 
$app_quit_request = 0; # End the application but not the FCGI process 

# workaround for known bug in libfcgi 
while (($ignore) = each %ENV) { } 

$fcgi_request = FCGI::Request(); 
#$fcgi_request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket); 

sub sig_handler { 
    my ($callpackage, $callfile, $callline) = caller; 
    if ($app_quit_request) { 
     $app_quit_request = 0; 
     goto ABORTLABEL; 
    } 

    $exit_requested = 1; 
    exit(0) if !$handling_request; 
} 

$SIG{USR1} = \&sig_handler; 
$SIG{TERM} = \&sig_handler; 
$SIG{PIPE} = 'IGNORE'; 

#The goal of fast cgi is to load the program once, and iterate in a loop for every request. 
while ($handling_request = ($fcgi_request->Accept() >= 0)) { 
    process_fcgi_request(); 
    $handling_request = 0; 
    last if $exit_requested; 
    #exit if -M $ENV{SCRIPT_FILENAME} < 0; # Autorestart 
} 

$fcgi_request->Finish(); 
exit(0); 
#=========================================================# 
sub process_fcgi_request() { 
    $fcgi_requests++; 

    # dispatch current request 
    my_app(); 

    $fcgi_request->Finish(); 
} 
#=========================================================# 
# let it think we are done, used by abort 
ABORTLABEL: 
    $fcgi_request->Finish(); 
#=========================================================# 

주요 요구 I는 계정 모듈에 로그인 기능 내부 예컨대 긴 깊이에 의해 호출 될 수있다 insidi 서브 모듈 내부에서 프로그램 실행을 중지 할 것이다. 물론 fcgi 프로세스가 종료 될 것이기 때문에 exit를 사용할 수 없습니다. 모든 오류를 시도하고 모듈을 모두 시도해보고 프로세스를 종료하는 die를 사용하십시오. 물론 각 하위의 리턴을 사용할 수는 있지만 fcgi에 대한 전체 프로그램을 다시 작성해야합니다.

답변

1

Perl에서 예외를 모델링하는 일반적인 방법은 die을 수신하므로 처리를 종료하지 않고 dieeval BLOCK 안에 호출하는 것입니다. 그것은 단지 eval을 종료하고 프로그램은 그 직후부터 계속 실행됩니다. 지금까지 보았 듯이, CPAN의 예외 처리 모듈은 대부분이 기본 기능을 둘러싼 래퍼로 다른 구문을 사용하거나 catch 블록을 더 쉽게 작성할 수 있습니다. 그러므로 나는 이것이 당신에게 효과가 없다는 것에 놀랐습니다. 당신은 실제로 그것들을 시도 했습니까? 아니면 그냥 die이 프로세스를 죽일 것이라고 가정 했습니까? 이름은 약간 '오해의 소지가 있습니다.'라는 말은 실제로 '예외를 던지기'를 의미하기 때문입니다. eval 외부에서 처리하면 인터프리터가 처리하고 유일한 응답은 프로세스를 종료하는 것입니다.

eval { 
    say "Hello world"; 
    die; 
    say "Not printed"; 
}; 
say "Is printed"; 

당신은 불구하고 eval 내부 exit를 호출하고 싶지 않아요. 그 어떤 것도 잡아 내지 못합니다.

FCGI에 대한 전체 제어 흐름을 다시 작성하는 것이 좋습니다. 코드의 수명주기가 크게 바뀌므로 변수 재사용이 제대로 작동하고 메모리 누출이 없는지 확인하기 위해 일정량의 수정 작업을 수행해야합니다. 나중에 이상한 버그를 추적하는 데 며칠을 보내는 것보다 먼저 그 일을하는 것이 좋습니다.

+0

감사 마태 복음 상세한 정보. 이 문제는 전체 OO 방식으로 다시 작성하기가 어려운 오래된 거대한 응용 프로그램의 문제이므로 하위 모듈 내부의 특정 지점에서 실행을 종료하면됩니다. 위의 논리는 현재 작동하지만 그 논리가 정확하고 수용 가능한 것입니까? – daliaessam

0

몇 가지 질문과 심층 연구 끝에이 솔루션을 얻었습니다. 이 코딩 예제를 통해 중첩 된 호출 수준에서 돌아갈 수 있습니다. 모듈 Scope::Upper은 XS이므로 빠릅니다. 이 코드를 실행하면

use Scope::Upper qw/unwind CALLER/; 

sub level1 { 
    print "before level 1 \n"; 
    level2(); 
    print "after level 1 \n"; 
} 

sub level2 { 
    print "before level 2 \n"; 
    level3(); 
    print "after level 2 \n"; 
} 

sub level3 { 
    print "before level 3 \n"; 
    level4(); 
    print "after level 3 \n"; 
} 

sub level4 { 
    print "before level 4 \n"; 

    #unwind CALLER 2; 

    my @frame; 
    my $i; 
    #$i++ while @frame = caller($i);# and $frame[0] ne "main"; 
    $i++ while @frame = caller($i); 
    #print "i=: $i \n"; 
    #unwind CALLER (@frame ? $i : $i - 1); 
    unwind CALLER $i-1; 

    print "after level 4 \n"; 
} 

print level1(); 

출력은 다음과 같습니다

before level 1 
before level 2 
before level 3 
before level 4 

당신이 사용하는 최대 수준으로 반환 할 수 있습니다

my intLevel = 2;  
unwind CALLER intLevel; 
관련 문제