package XAS::Lib::App::Daemon; our $VERSION = '0.02'; use Try::Tiny; use Pod::Usage; use Hash::Merge; use Getopt::Long; use POSIX 'setsid'; use XAS::Lib::Pidfile; use XAS::Class debug => 0, version => $VERSION, import => 'class CLASS', base => 'XAS::Lib::App', utils => ':process', constants => 'TRUE FALSE', accessors => 'daemon pid', ; # ---------------------------------------------------------------------- # Public Methods # ---------------------------------------------------------------------- sub define_signals { my $self = shift; $SIG{'INT'} = \&signal_handler; $SIG{'QUIT'} = \&signal_handler; $SIG{'TERM'} = \&signal_handler; $SIG{'HUP'} = \&signal_handler; } sub define_pidfile { my $self = shift; my $script = $self->env->script; $self->log->debug('entering define_pidfile()'); $self->{pid} = XAS::Lib::Pidfile->new(-pid => $$); if (my $num = $self->pid->is_running()) { $self->throw_msg( dotid($self->class). '.define_pidfile.runerr', 'pid_run_error', $script, $num ); } $self->pid->write() or $self->throw_msg( dotid($self->class) . '.define_pidfile.wrterr', 'pid_write_error', $self->pid->file ); $self->log->debug('leaving define_pidfile()'); } sub define_daemon { my $self = shift; # become a daemon... # interesting, "daemonize() if ($self->daemon);" doesn't work as expected $self->log->debug("before pid = " . $$); if ($self->daemon) { daemonize(); } $self->log->debug("after pid = " . $$); } sub run { my $self = shift; my $rc = $self->SUPER::run(); $self->pid->remove(); return $rc; } # ---------------------------------------------------------------------- # Private Methods # ---------------------------------------------------------------------- sub _default_options { my $self = shift; my $options = $self->SUPER::_default_options(); $self->{daemon} = FALSE; $options->{'daemon'} = \$self->{daemon}; $options->{'cfgfile=s'} = sub { my $cfgfile = File($_[1]); $self->env->cfgfile($cfgfile); }; $options->{'pidfile=s'} = sub { my $pidfile = File($_[1]); $self->env->pidfile($pidfile); }; return $options; } 1; __END__ =head1 NAME XAS::Lib::App::Daemon - The base class to write daemons within the XAS environment =head1 SYNOPSIS use XAS::Lib::App::Daemon; my $app = XAS::Lib::App::Daemon->new(); $app->run(); =head1 DESCRIPTION This module defines an operating environment for daemons. A daemon is a Unix background process without a controlling terminal. Windows really doesn't have a concept for this behavior. For running background jobs on Windows please see L<XAS::Lib::App::Services|XAS::Lib::App::Services>. This module is also single threaded, it doesn't use POE to provide an async environment. If you need that, then see the above module. This inherits from L<XAS::Lib::App|XAS::Lib::App>. Please see that module for additional documentation. =head1 METHODS =head2 define_pidfile This method sets up the pid file for the process. By default, this file is named $XAS_RUN/<$0>.pid. This can be overridden by the --pidfile option. =head2 define_signals This method sets up basic signal handling. By default this is only for the INT, TERM, HUP and QUIT signals. =head2 define_daemon This method will cause the process to become a daemon. =head1 OPTIONS This module handles these additional options. =head2 --cfgfile This defines an optional configuration file. =head2 --pidfile This defines the pid file for recording the pid. =head2 --daemon Become a daemon. =head1 SEE ALSO =over 4 =item L<XAS|XAS> =back =head1 AUTHOR Kevin L. Esteb, E<lt>kevin@kesteb.usE<gt> =head1 COPYRIGHT AND LICENSE Copyright (C) 2014 Kevin L. Esteb This is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0. For details, see the full text of the license at http://www.perlfoundation.org/artistic_license_2_0. =cut