Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

A few questions regarding Proc::Daemon

by walkingthecow (Friar)
on Nov 07, 2013 at 23:10 UTC ( [id://1061640]=perlquestion: print w/replies, xml ) Need Help??

walkingthecow has asked for the wisdom of the Perl Monks concerning the following question:

Good afternoon monks! Before I ever resort to asking for help, I always try my best to do my own research and figure things out myself. I am running into a wall here simply because the ways in which is Proc::Daemon used are so wildly different, and the CPAN documentation is rather limited.

Before I go further with my questions, I will give you a chance to see the code I have thus far written:
#!/usr/bin/env perl use strict; use warnings; use POSIX; use Proc::Daemon; use Proc::PID::File; use Log::Dispatch; use Log::Dispatch::File; use Config::General; use Sys::Hostname; use Data::Dumper; use File::Spec; my $config_file = '/etc/divinity/divinityd.conf'; # First we deal with config file and command line options # Command line options override config file. my $conf = Config::General->new($config_file); my %config = $conf->getall; my $pid_file = $config{pid_file} || '/var/run/divinityd.pid'; my $hostname = hostname; # First we deal with required config options my $method = $config{method} or config_err("no method specified"); my ($server_url,$validation_key,$scp_host,$log_file,$log_level); if ( $method eq "https" ) { $server_url = $config{server_url} or config_err("no server_url spe +cified"); $validation_key = $config{validation_key} or config_err("no valida +tion_key specified"); } if ( $method eq "scp" ) { $scp_host = $config{scp_host} or config_err("no scp_host specified +"); } my $node_name = $config{node_name} || $hostname; my $user = $config{user} || 'divinityd'; my $group = $config{group} || 'divinityd'; my $logging = $config{logging} || 'on'; if ( $logging eq "on" ) { $log_file = $config{log_file} || '/var/log/divinityd.log'; $log_level = $config{log_level} || 'warning'; } my $fork = $config{fork} || 'yes'; my $child_num = $config{child_num} || 10; my $proxy = $config{proxy} || $ENV{PROXY}; my $interval = $config{interval} || '300'; my $log = Log::Dispatch->new( callbacks => sub { my %h=@_; return "[".strftime("%F %R", localtime(time))."] " .$hostname." ".$h{message}."\n"; } ); $log->add( Log::Dispatch::File->new( name => 'divinityd_log', min_level => $log_level, mode => 'append', filename => $log_file, ) ); # # Setup signal handlers so that we have time to cleanup before shuttin +g down # my $keep_going = 1; $SIG{HUP} = sub { $log->warning("Caught SIGHUP: exiting gracefully"); $keep_going = 0; }; $SIG{INT} = sub { $log->warning("Caught SIGINT: exiting gracefully"); $keep_going = 0; }; $SIG{QUIT} = sub { $log->warning("Caught SIGQUIT: exiting gracefully"); $keep_going = 0; }; my $daemon = Proc::Daemon->new( pid_file => $pid_file, ); $daemon->Init; while ( $keep_going ) { $log->warning("TEST\n"); sleep(5); } sub config_err { my $message = $_[0]; print STDERR $message; die("\n"); } sub dienice ($) { my ($package, $filename, $line) = caller; $log->critical("$_[0] at line $line in $filename"); die $_[0]; }
Now, as it stands at this point, when I run my daemon (as root, with sudo, or as a regular user), then do a 'ps -ef | grep perl', I see that my daemon is not running, and nothing has been logged. However, when I comment out the daemon aspect of the script, everything seems to work as expected. So, first, I am not sure why it's not daemonizing.

Second, I am handling SIGNALS myself, but I am wondering if Proc::Daemon handles that for me, or if there is a method of doing so with Proc::Daemon. I feel that I am using mixed methods here (i.e., how to do it without Proc::Daemon mixed with the way it is done with Proc::Daemon). Basically, I'd like for the script to die gracefully (close filehandles, remove pid file, etc) on any signal or an ARGV of stop, and I'd like for the daemon to give a status report (i.e., "divinityd runnin (PID#)" when someone does './divinityd status'. Below is the code I was using to check status, stop, etc...
my $daemon = Proc::Daemon->new( pid_file => $pid_file, ); $daemon->Init; if ( $ARGV[0] eq "stop ) { $daemon->Kill_Daemon(); } elsif ( $ARGV[0] eq "status" ) { $daemon->Status($pid_file); } elsif ( $ARGV[0] eq "start" ) { while ( $keep_going ) { $log->warning("TEST\n"); sleep(5); } }
The problem I was running into here was that when one would check the status of the daemon, the pid file had already been created, thus the status would say running, even if the daemon wasn't actually running.

Basically, I am just wondering what aspects of what I am doing are just completely wrong. Where I am wrong, and possibly if anyone knows any good newer resources on how to use Proc::Daemon.

Thanks in advance monks for any help you can give me and have a wonderful day!

UPDATE

My apologies for answering my own question, or at least it seems that I am getting there anyway. I noticed that Proc::Daemon documentation says:

6. The second child closes all open file descriptors (unless you define dont_close_fh and/or dont_close_fd

So, moving my code around a bit I add the log file after Proc::Daemon::Init(); However, I am still trying to figure out how to take a command line 'stop' or 'status' and have the logging work outside of my 'while ( $keep_going )' loop. If/when I figure that out, I will post updated code.

Replies are listed 'Best First'.
Re: A few questions regarding Proc::Daemon
by afoken (Chancellor) on Nov 08, 2013 at 09:09 UTC

    Have a look at daemontools. Essentially, daemontools take care of start, stop, restart, logging, sending signals, "becoming a daemon". You don't have to reinvent all of this. Just write the code that "does the job". Send log output to STDOUT or STDERR. Don't fork background processes.

    The concept of daemontools is often copied, you can find a very similar implementation in runit standalone and in busybox, systemd also expect daemons to run under its control, so does upstart.

    All of these systems need extra work for daemons that fork themselves to the "background". Even a classic init that controls a daemon expect it not to fork to "background". The "going to background" is only really meaningful when starting daemons manually from a (virtual) terminal or the console, and there, a small shell script using kill, fork, exec, nohup and i/o redirection makes much more sense. This script can also be used from classic init scripts.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
      I'm trying to write a daemon, not trying to replace systemd, initd, upstart, etc. Your suggestion seems way overkill as an answer to my question.
        I'm trying to write a daemon, not trying to replace systemd, initd, upstart, etc.

        Yes, I know.

        Your suggestion seems way overkill as an answer to my question.

        No. You did not understand my answer. Your daemon is doing too much work. Let the operating system (i.e. daemontools, systemd, init, upstart, ...) handle forking, logging, restarting. Write your daemon so that it does not fork to "background", does not re-invent logging, does not re-invent sending signals to a running process, does not re-invent configuration, etc. Have a look at the daemontools and services sections of the djb way.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1061640]
Approved by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (7)
As of 2024-04-23 10:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found