4

Mojolicious::Liteは、websocket エンドポイントを含む単純なベースのサーバーで作業しています。

Websocket 接続を正常に終了し、クライアント (Java アプリケーション) での例外を回避するために、いくつかの終了シグナルを処理したいと考えています。

を使用して以前のサーバーで慣れていたように、シグナルハンドラーを定義しようとしましたHTTP::Daemon。問題は、それらが無視されているように見えることです。モジョリシャス層で再定義されたのかもしれませんが、まだ参考文献は見つかりませんでした。

終了メッセージが表示されることを期待していますが、表示されません

[Mon Mar 23 14:01:28 2020] [info] Listening at "http://*:3000"
Server available at http://127.0.0.1:3000
^C  # <-- i want to see my signal received message here if type Ctrl-c

SIGINTサーバーが端末でフォアグラウンドにあるときに入力して直接送信しCtrl-Cています。サーバーを正常に終了できます(たとえば、cronまたはその他の表示のない手段によって開始された場合)kill <pid>.

以前のいくつかのサーバーでは、以下を処理することで非常に徹底的にしようとしました:

  • HUP設定をリロードするために現在使用されているハイジャックされたシグナル
  • SIGINTCtrl+C
  • SIGQUITCtrl-\
  • SIGABRT例: ライブラリの異常終了
  • SIGTERM外部終了要求 - 「友好的」kill(残忍な反対による)kill -9
  • TSTPCtrl-Z でサスペンド
  • CONTまたは を使用して Ctrl-Z から再開するfg場合bg

これらのハンドラーはすべて、プログラムとニーズに応じて、リソースをクリーニングして正常に終了し、データの一貫性を確保したり、外部変更後に構成またはデータ モデルをリロードしたりできます。

Mojo::IOLoop::Signal«ノンブロッキングシグナルハンドラー»というパッケージを見つけましたが、それは別のもののようです。違う?

これが私の簡略化されたコードです(単純な で実行されますperl ws_store_test.pl daemon):

ファイル ws_store_test.pl

# Automatically enables "strict", "warnings", "utf8" and Perl 5.10 features
use Mojolicious::Lite;

my $store = {};
my $ws_clients = {};

sub terminate_clients {
    for my $peer (keys %$ws_clients){
        $ws_clients->{$peer}->finish;
    }
}

$SIG{INT} = sub {
    say "SIGINT";  # to be sure to display something
    app->log->info("SIGINT / CTRL-C received. Leaving...");
    terminate_clients;
};
$SIG{TERM} = sub {
    say "SIGTERM"; # to be sure to display something
    app->log->info("SIGTERM - External termination request. Leaving...");
    terminate_clients;
};

# this simulates a change on datamodel and notifies the clients
sub update_store {
    my $t = localtime time;
    $store->{last_time} = $t;
    for my $peer (keys %$ws_clients){
        app->log->debug(sprintf 'notify %s', $peer);
        $ws_clients->{$peer}->send({ json => $store
                                       });
    }
}

# Route with placeholder - to test datamodel contents
get '/:foo' => sub {
  my $c   = shift;
  my $foo = $c->param('foo');
  $store->{$foo}++;
  $c->render(text => "Hello from $foo." . (scalar keys %$store ? " already received " . join ', ', sort keys %$store : "") );
};

# websocket service with optional parameter
websocket '/ws/tickets/*id' => { id => undef } => sub {
    my $ws = shift;
    my $id = $ws->param('id');

    my $peer = sprintf '%s', $ws->tx;
    app->log->debug(sprintf 'Client connected: %s, id=%s', $peer, $id);
    $ws_clients->{$peer} = $ws->tx;
    $store->{$id} = {};

    $ws->on( message => sub {
        my ($c, $message) = @_;
        app->log->debug(sprintf 'WS received %s from a client', $message);
             });

    $ws->on( finish => sub {
        my ($c, $code, $reason) = @_;
        app->log->debug(sprintf 'WS client disconnected: %s - %d - %s', $peer, $code, $reason);
        delete $ws_clients->{$peer};
             });
};

plugin Cron => ( '* * * * *' => \&update_store );

# Start the Mojolicious command system
app->start;
4

1 に答える 1