3

I run a small multiplayer card game with around 500 users at peak times:

screenshot

The client is in Flash and the server is in Perl.

The Perl server binds to port 8080, i.e. only 1 instance of it can be started (important detail).

The Perl server poll()s TCP-sockets and forks only once - at the startup by calling this method:

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;

It runs on CentOS 5.6 Linux / 64 bit, PostgreSQL 8.4.8 and Perl 5.8.8.

Because my budget is small and I had enough troubles already, I want to use as little additional software as possible - so that I can change hosters or reinstall my cheapo server quickly. That is why I for example just log to /tmp/pref.txt instead of installing syslog-ng. And that is why I'd like to use /etc/inittab for restarting my Perl daemon.

My Perl daemon runs mostly stable, but approx. once a week it can crash with a

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

Since I'm tired of restarting the server manually, I've tried to add it to the /etc/inittab:

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

(and I've added a nightly cronjob to "pkill pref.pl" in the hope to refresh perl this way).

Unfortunately this does not work as expected - in the /var/log/messages I see that the script is being started again and again:

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

What am I doing wrong here? I was hoping to being able to use /etc/inittab here, because I remember using it for a similar situation at work few years ago (also with a Perl daemon) and it worked well then...

Thank you! Alex

UPDATE:

My game is not crashing, perl interpreter does (but not often, once a week).

My question is about how to run a Perl daemon (i.e. a Perl script that forks once in the beginning and then binds to a TCP port) from /etc/inittab?

Alexander Farber
  • 714
  • 4
  • 16
  • 38

2 Answers2

1

Just remove the fork() from the code. To this point you've written a piece of code that you want to detatch from the console and run in the background. However, when processes run from inittab they need to stay attached. If you remove the fork(), it will stay attached to init and init will be able to monitor/start/stop/restart properly

jj33
  • 11,038
  • 1
  • 36
  • 50
  • That makes sense, thank you - I'll try it in few hours. Do you think I still need setsid() and chdir('/') and umask(0)? And do I need to redirect STDOUT and STDERR as above or can I just run "pref.pl 2>&1 > /tmp/pref.txt" from /etc/inittab? – Alexander Farber Jun 02 '11 at 20:33
  • Thank you, now my perl daemon works with /etc/inittab I've removed fork() and used this line: pref:3:respawn:/bin/su -c '/usr/local/pref/pref.pl >/tmp/pref.txt 2>&1' nobody – Alexander Farber Jun 02 '11 at 22:27
0

I can't speak to your inittab solution, hopefully someone else can, but I do want to suggest you look at "File::Pid" as something to add to your script - after the daemonize call (this is important - your process ID changes after a fork).

use File::Pid;

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

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

This gives you a couple things - one it ensures you don't run two copies of it at the same time (which you said was a big deal) and it also would let you safely call this program whenever you wanted providing a simple keepalive. Just call your code from cron every 10 minutes, and it'll do nothing if it's running, or restart it if it's down.

Neil Neely
  • 466
  • 3
  • 5
  • Thank you, but actually I already print $$ to a /tmp/pref.pid in my script. And I thought about an every 10-mins cronjob too, but hope to find an /etc/inittab solution as well – Alexander Farber Jun 02 '11 at 20:18