Create Daemon (service) from a Perl script using Daemon::Control
It is quite easy to turn a perl script into a daemon on Linux that you can manage with systemctl.
Original script
examples/daemon/original.pl
#!/usr/bin/env perl use strict; use warnings; main(); sub main { my $logfile = 'process.log'; my $continue = 1; $SIG{INT} = sub { logger('INT received'); $continue = 0; }; while ($continue) { logger(''); sleep 1; } } sub logger { my ($text) = @_; if (open my $fh, '>>', 'process.log') { print $fh scalar localtime(); print $fh " $text\n"; } }
This is a very simple script that has an infinite loop writing to a log file every second. If you press Ctr-C then the script will capture that signal (the INT signal), set the $continue flag to 0 and the loop will stop and then the program as well. This is a graceful termination of the process.
How can we convert this something that we can run as a service?
HUP and TERM instead of INT
Instead of expecting an INT signal which is sent when your press Ctrl-C while starting at a ru8nning process we are expecting two other signals. the TERM signal will be received when we try to "stop" the service and when we try to "restart" it.
The HUP is received when we try to "reload" the service. Most service would re-read their configuration file when they are reloaded. We'll do that too.
The application:
examples/daemon/local.pl
#!/usr/bin/env perl use strict; use warnings; use File::Basename qw(dirname); use File::Spec::Functions qw(catfile); main(); my $code; sub main { $code = read_config(); logger('starting'); my $continue = 1; $SIG{TERM} = sub { logger('TERM received'); $continue = 0; }; $SIG{HUP} = sub { logger('HUP received'); $code = read_config(); }; while ($continue) { logger(''); sleep 1; } } sub logger { my ($text) = @_; if (open my $fh, '>>', 'process.log') { print $fh scalar localtime(); print $fh " $code - $text\n"; } } sub read_config { my $config_file = 'config.txt'; open my $fh, '<', $config_file or die "Could not open '$config_file'\n"; my $code = <$fh>; chomp $code; return $code; }
The code to create the dameon is the following, using Daemon::Control
examples/daemon/daemon.pl
use warnings; use strict; use Daemon::Control; use File::Basename qw(dirname); use File::Spec::Functions qw(catfile); my $dir = dirname(__FILE__); exit Daemon::Control->new( name => "My Daemon", lsb_start => '$syslog $remote_fs', lsb_stop => '$syslog', lsb_sdesc => 'My Daemon Short', lsb_desc => 'My Daemon controls the My Daemon daemon.', path => $dir, program => catfile($dir, 'local.pl'), program_args => [ ], pid_file => '/tmp/mydaemon.pid', stderr_file => '/tmp/mydaemon.out', stdout_file => '/tmp/mydaemon.out', fork => 2, )->run;
This version is assumed to be located in the same directory as the script itself.
$ perl daemon.pl Syntax: daemon.pl [start|stop|restart|reload|status|foreground|show_warnings|get_init_file|help]
Starting the process:
$ perl daemon.pl start
You can chenge the content of "config.txt" while the service is running and then execute
$ perl daemon.pl reload
It will re-read the configuration file and continue running.
examples/daemon/local_process.log
Mon Feb 15 12:42:56 2021 one - starting Mon Feb 15 12:42:56 2021 one - Mon Feb 15 12:42:57 2021 one - Mon Feb 15 12:42:58 2021 one - HUP received Mon Feb 15 12:42:59 2021 two - Mon Feb 15 12:43:00 2021 two - Mon Feb 15 12:43:01 2021 two - TERM received Mon Feb 15 12:43:02 2021 two - starting Mon Feb 15 12:43:03 2021 two - Mon Feb 15 12:43:04 2021 two - Mon Feb 15 12:43:05 2021 two -TERM received
$ perl daemon.pl stop
System-wide version
Published on 2021-02-15