fastcgiマネージャーとの通信

説明



FCGI :: ProcManagerの小さな拡張で、fcgiプロセスマネージャーにアクセスできます。 サードパーティのプログラムとマネージャーとの通信には、ソケットが使用されます。



落とし穴



FCGI :: ProcManagerモジュールは、着信要求ハンドラーを生成するために使用されます。 現在のプロセスはマネージャーです。 最初からハンドラー(n_processes個)を生成し、戦闘中の死者を監視することでその数を維持します。 これらの目的のために、 waitを使用します。 これが問題のある場所です。 スレッドが開始されると、マネージャーはwaitを呼び出してブロックされます。 あなたは信号を介してのみそれに到達することができます 。 シグナルハンドラーでコードを賢明かつ正確に実行する必要があります。govnokodを駆動するのは良くありません。 そのため、別の通信チャネルを確立する必要があります。





実装



たとえば、マネージャーにソケットをリッスンさせてみましょう。 これを行うには、マネージャーにブロックしないように強制する必要があります。 pm_wait関数は、FCGI :: ProcManagerで待機します。

sub pm_wait { my ($this) = self_or_default(@_); # wait for the next server to die. next if (my $pid = wait()) < 0; # notify when one of our servers have died. delete $this->{PIDS}->{$pid} and $this->pm_notify("server (pid $pid) exited with status $?"); return $pid; }
      
      







wait呼び出しをwaitpidに置き換えて、コードを貼り付ける必要があります。 マネージャーは別のポートを開いてリッスンする必要があり、スタンバイモードでは定期的に子孫を見てポートをリッスンする必要があります。 pm_wait関数のバージョンを作成し、FCGI :: ProcManagerモジュールの同じ名前の関数をモンキーパッチに置き換えます。 メッセージへの応答として、プロジェクトライブラリを更新した後、すべての子孫をオーバーロードします。

 use FCGI; use FCGI::ProcManager; use IO::Select; use IO::Socket; use POSIX ":sys_wait_h"; #use Module::Refresh; use feature ':5.14'; use strict; # For fastcgi app my $socket = FCGI::OpenSocket( ":9019", 5 ); my $request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket, FCGI::FAIL_ACCEPT_ON_INTR ); # To communicate with the manager my $server = IO::Socket::INET->new(LocalPort => '9034', Type => SOCK_STREAM, Reuse => 1, Listen => 1) or die "Couldn't start messange server $@\n"; my $select = IO::Select->new($server); # Patch my $pm_wait = sub { my ($pm) = @_; my $pid; while (1) { last if ($pid = waitpid(-1, WNOHANG)); foreach my $client ($select->can_read(1)) { if ($client == $server) { $client = $server->accept(); $select->add($client); } else { my $msg = <$client>; chomp $msg; if ($msg eq 'reload') { #my $refresher = Module::Refresh->new(); #my @module_list = qw( MyLib1.pm My/Lib2.pm ); #foreach my $module_name (@module_list){ # $refresher->refresh_module($module_name); #} $pm->sig_manager('HUP'); } print $client "done!\n"; $select->remove($client); close $client; } } } # notify when one of our servers have died. delete $pm->{PIDS}->{$pid} and $pm->pm_notify("server (pid $pid) exited with status $?"); return $pid; }; no strict 'refs'; *{'FCGI::ProcManager::pm_wait'} = $pm_wait; use strict 'refs'; my $pm = FCGI::ProcManager->new( ); $pm->pm_manage( n_processes => 3, pm_title => 'perl-fcgi-pm', die_timeout => 10 ); while ( $request->Accept() >= 0 ) { $pm->pm_pre_dispatch(); print "Content-Type: text/plain\n\n"; print "server works"; $pm->pm_post_dispatch(); } FCGI::CloseSocket($socket); close $server;
      
      







テストのコードは次のとおりです。

 use IO::Socket; use feature ':5.14'; use strict; my $socket = new IO::Socket::INET(Proto => "tcp", Type => SOCK_STREAM, PeerPort => 9034, PeerAddr => "127.0.0.1" ) or die "Can't connect: $!"; #my $msg = $ARGV[0]; my $msg = 'reload'; if ($msg) { print $socket "$msg\n"; my $answer = <$socket>; say "Answer: ".$answer; }
      
      







合計



したがって、fastcgiプロセスマネージャにメッセージを送信できます(プロトコルは自分で作成できます)。 これは、アプリケーションの現在の構成を照会するために使用できます。 プロジェクトライブラリをリロードします(この例ではコメントアウトされています)。 ハンドラーの数を増減できます

 $pm->{n_processes} = 10; $pm->sig_manager('HUP');
      
      





さて、プロファイリングのオン/オフなどのささいなこと。 もちろん、これらのタスクは他の方法で解決できます。



それを行うには複数の方法があります



All Articles