How to Run a Perl Script as a System Daemon in Linux

How can I run a Perl script as a system daemon in linux?

The easiest way is to use Proc::Daemon.

#!/usr/bin/perl

use strict;
use warnings;
use Proc::Daemon;

Proc::Daemon::Init;

my $continue = 1;
$SIG{TERM} = sub { $continue = 0 };

while ($continue) {
#do stuff
}

Alternately you could do all of the things Proc::Daemon does:

  1. Fork a child and exits the parent process.
  2. Become a session leader (which detaches the program from the controlling terminal).
  3. Fork another child process and exit first child. This prevents the potential of acquiring a controlling terminal.
  4. Change the current working directory to "/".
  5. Clear the file creation mask.
  6. Close all open file descriptors.

Integrating with the runlevel system is easy. You need a script like the following (replace XXXXXXXXXXXX with the Perl script's name, YYYYYYYYYYYYYYYYYYY with a description of what it does, and /path/to with path to the Perl script) in /etc/init.d. Since you are using CentOS, once you have the script in /etc/init.d, you can just use chkconfig to turn it off or on in the various runlevels.

#!/bin/bash
#
# XXXXXXXXXXXX This starts and stops XXXXXXXXXXXX
#
# chkconfig: 2345 12 88
# description: XXXXXXXXXXXX is YYYYYYYYYYYYYYYYYYY
# processname: XXXXXXXXXXXX
# pidfile: /var/run/XXXXXXXXXXXX.pid
### BEGIN INIT INFO
# Provides: $XXXXXXXXXXXX
### END INIT INFO

# Source function library.
. /etc/init.d/functions

binary="/path/to/XXXXXXXXXXXX"

[ -x $binary ] || exit 0

RETVAL=0

start() {
echo -n "Starting XXXXXXXXXXXX: "
daemon $binary
RETVAL=$?
PID=$!
echo
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/XXXXXXXXXXXX

echo $PID > /var/run/XXXXXXXXXXXX.pid
}

stop() {
echo -n "Shutting down XXXXXXXXXXXX: "
killproc XXXXXXXXXXXX
RETVAL=$?
echo
if [ $RETVAL -eq 0 ]; then
rm -f /var/lock/subsys/XXXXXXXXXXXX
rm -f /var/run/XXXXXXXXXXXX.pid
fi
}

restart() {
echo -n "Restarting XXXXXXXXXXXX: "
stop
sleep 2
start
}

case "$1" in
start)
start
;;
stop)
stop
;;
status)
status XXXXXXXXXXXX
;;
restart)
restart
;;
*)
echo "Usage: $0 {start|stop|status|restart}"
;;
esac

exit 0

Daemonize a perl script at startup Linux

The problem was that @INC hadn't fully loaded all of the modules by the time my script was called, and so my daemon wasn't running. I used the PERL5LIB command to add the appropriate directories.

PERL5LIB='/perl:/custom/lib:/usr/local/lib64/perl5' /var/myfolder/myscript.pl &

where /perl; /custom/lib and /usr/local/lib64/perl5 are the directories which were missing from @INC

Run a Perl script in the background and send it commands

I would probably use the bones of the answer you refer to, but add:

  • a handler for SIGHUP which re-reads the config file of IPs to suppress, and,

  • a handler for SIGUSR1 which reports how much time there is remaining.

So, it would look like this roughly:

#!/usr/bin/perl

use strict;
use warnings;
use Proc::Daemon;

Proc::Daemon::Init;

my $continue = 1;
################################################################################
# Exit on SIGTERM
################################################################################
$SIG{TERM} = sub { $continue = 0 };

################################################################################
# Re-read config file on SIGHUP
################################################################################
$SIG{HUP} = sub {
# Re-read some config file - probably using same sub that we used at startup
open(my $fh, '>', '/tmp/status.txt');
print $fh "Re-read config file\n";
close $fh;
};

################################################################################
# Report remaining time on SIGUSR1
################################################################################
$SIG{USR1} = sub {
# Subtract something from something and report difference
open(my $fh, '>', '/tmp/status.txt');
print $fh "Time remaining = 42\n";
close $fh;
};

################################################################################
# Main loop
################################################################################
while ($continue) {
sleep 1;
}

You would then send the HUP signal or USR1 signal with:

pkill -HUP daemon.pl

or

pkill -USR1 daemon.pl 

and look in /tmp/status.txt for the output from the daemon. The above commands assume you stored the Perl script as daemon.pl - adjust if you used a different name.

Or you could have the daemon write its own pid in a file on startup and use the -F option to pkill.

Run script as daemon with proc::Daemon module

It seems like you don't have a loop for your code. Your program just exit after running filefind() and readData(). You can comments Proc::Daemon::Init; to see the procedure

To solve the problem, you can add a loop at the end:

while (1) {
sleep 10;
}

How to get PID of perl daemon in init script?

Thank you to the suggestions from zdim and Hakon. They are certainly workable, and got me on the right track, but ultimately I went a different route. Rather than relying on $!, I used ps and awk to get the PID, as follows:

DAEMON='/path/to/perl/script.pl'

start() {
$DAEMON > /dev/null 2>&1
PID=`ps aux | grep -v 'grep' | grep "$DAEMON" | awk '{print $2}'`
echo $PID > /var/run/mem-monitor.pid
}

This works and satisfies my OCD! Note the double quotes around "$DAEMON" in grep "$DAEMON".

Running script constantly in background: daemon, lock file with crontab, or simply loop?

Let's assume you take the continuous loop route. You rejigger your program to be one infinite loop. You sleep for a certain amount of time, then wake up and process your database files, and then go back to sleep.

You now need a mechanism to make sure your program is still up and running. This could be done via something like inetd.

However, your program basically does a single task, and does that task repeatedly through the day. This is what crontab is for. The inetd mechanism is for servers that are waiting for a client, like https or sshd. In these cases, you need a mechanism to recreate the server process as soon as it dies.

One way you can improve your lockfile mechanism is to include the PID with it. For example, in your Perl script you do this:

open my $lock_file_fh, ">", LOCK_FILE_NAME;
say {$lock_file_fh} "$$";
close $lock_file_fh;

Now, if your crontab sees the lock file, it can test to see if that process ID is still running or not:

if [ -f $lock_file ]
then
pid=$(cat $lock_file)
if ! ps -p $pid
then
rm $lock_file
fi
restart_program
else
restart_program
fi


Related Topics



Leave a reply



Submit