web-dev-qa-db-ja.com

/ etc / inittabからPerlスクリプト(ソケットデーモン)を再起動します

私は 小さなマルチプレイヤーカードゲーム ピーク時に約500人のユーザーで実行します:

screenshot

クライアントはFlashで、サーバーはPerlです。

Perlサーバーはポート8080にバインドします。つまり、起動できるインスタンスは1つだけです(重要な詳細)。

PerlサーバーはTCPソケットとフォークを1回だけポーリングします-起動時に次のメソッドを呼び出します。

sub daemonize {
    die "Can not fork: $!\n" unless defined (my $child = fork());
    # the parent should die
    exit 0 if $child;

    setsid();
    open(STDIN, '</dev/null');
    open(STDOUT, '>/tmp/pref.txt');
    open(STDERR, '>&STDOUT');
    chdir('/');
    umask(0);
}
....
$tcpSocket = IO::Socket::INET->new(Proto     => 'tcp',
                                   LocalPort => 8080,
                                   Listen    => SOMAXCONN,
                                   ReuseAddr => 1,
                                   );
die "Can not create listening TCP socket: $!\n"
        unless defined $tcpSocket;

CentOS 5.6 Linux/64ビット、PostgreSQL 8.4.8、Perl5.8.8で動作します。

予算が少なく、すでに十分なトラブルが発生しているため、追加のソフトウェアをできるだけ少なくして、ホスティング業者を変更したり、安価なサーバーをすばやく再インストールしたりしたいと考えています。そのため、たとえば、syslog-ngをインストールする代わりに/tmp/pref.txtにログを記録します。そのため、Perlデーモンを再起動するために/ etc/inittabを使用したいと思います

私のPerlデーモンはほとんど安定して動作しますが、約週に一度、

May 29 11:06:46 myhost kernel: pref.pl[3113]: segfault at 00007fffa21e6fd8 rip 0000003cce274460 rsp 00007fffa21e6fd0 error 6

サーバーを手動で再起動するのにうんざりしているので、サーバーを/ etc/inittabに追加しようとしました。

pref:3:respawn:/bin/su -c '/usr/local/pref/pref.pl' nobody

(そして、この方法でPerlを更新することを期待して、「pkill pref.pl」に毎晩cronジョブを追加しました)。

残念ながら、これは期待どおりに機能しません-/ var/log/messagesで、スクリプトが何度も開始されていることがわかります。

Jun  2 18:55:56 myhost init: Id "pref" respawning too fast: disabled for 5 minutes
Jun  2 19:00:58 myhost init: Id "pref" respawning too fast: disabled for 5 minutes
Jun  2 19:06:02 myhost init: Id "pref" respawning too fast: disabled for 5 minutes

私はここで何が間違っているのですか?ここで/ etc/inittabを使用できることを望んでいました。数年前に職場で同様の状況で使用したことを覚えており(Perlデーモンでも)、その後はうまく機能しました...

ありがとうございました!アレックス

更新:

私のゲームはクラッシュしていませんが、Perlインタープリターはクラッシュします(ただし、頻繁ではありませんが、週に1回)。

私の質問は、Perlデーモンを実行する方法についてです(つまり、最初に一度フォークしてからTCPポート)from/etc/inittab?

3

コードからfork()を削除するだけです。ここまでで、コンソールから切り離してバックグラウンドで実行するコードを作成しました。ただし、プロセスがinittabから実行される場合は、接続を維持する必要があります。 fork()を削除すると、initに接続されたままになり、initは適切に監視/開始/停止/再起動できるようになります。

1
jj33

私はあなたのinittabソリューションと話すことができません、うまくいけば他の誰かが話すことができますが、デーモン呼び出しの後にスクリプトに追加するものとして「File :: Pid」を見るように提案したいと思います(これは重要です-あなたのプロセスIDフォーク後に変更されます)。

use File::Pid;

my $pidfile = File::Pid->new({
                            file => '/var/run/myprogram.pid',
                            pid => $$,
                            });

if ( my $num = $pidfile->running ) {
    exit;
}
$pidfile->write;

これにより、いくつかのことが得られます。1つは、2つのコピーを同時に実行しないようにすることです(これは大したことです)。また、単純なキープアライブを提供したいときはいつでも、このプログラムを安全に呼び出すことができます。 10分ごとにcronからコードを呼び出すだけで、実行中の場合は何も実行されず、ダウンしている場合は再起動します。

0
Neil Neely