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:
- Fork a child and exits the parent process.
- Become a session leader (which detaches the program from the controlling terminal).
- Fork another child process and exit first child. This prevents the potential of acquiring a controlling terminal.
- Change the current working directory to
"/"
. - Clear the file creation mask.
- 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
Can Windows Containers Be Hosted on Linux
How to Install Gcc 4.9.2 on Rhel 7.4
What Is the Meaning of So_Reuseaddr (Setsockopt Option) - Linux
What Does the Number in Parentheses Shown After Unix Command Names in Manpages Mean
Exploring Docker Container'S File System
"Failed to Load Platform Plugin "Xcb" " While Launching Qt5 App on Linux Without Qt Installed
How to Recursively Grep All Directories and Subdirectories
Finding Which Process Was Killed by Linux Oom Killer
How to Debug the Linux Kernel With Gdb and Qemu
What Happens If There Is No Exit System Call in an Assembly Program
How to Install Latest Version of Git on Centos 8.X/7.X/6.X
"Unable to Find Remote Helper For 'Https'" During Git Clone