Acme-Ghost
view release on metacpan or search on metacpan
lib/Acme/Ghost.pm view on Meta::CPAN
my $g = Acme::Ghost->new(
logfile => '/tmp/daemon.log',
pidfile => '/tmp/daemon.pid',
user => 'nobody',
group => 'nogroup',
);
$g->daemonize;
$g->log->info('Oops! I am Your Ghost');
=head1 DESCRIPTION
An yet another view to daemon processes
=head2 new
my $g = Acme::Ghost->new(
name => 'myDaemon',
user => 'nobody',
group => 'nogroup',
pidfile => '/var/run/myDaemon.pid',
logfile => '/var/log/myDaemon.log',
ident => 'myDaemon',
logopt => 'ndelay,pid',
facility => 'user',
logger => Mojo::Log->new,
loglevel => 'debug',
loghandle => IO::Handler->new,
);
=head1 ATTRIBUTES
This class implements the following attributes
=head2 facility
facility => 'user',
This attribute sets facility for logging
See L<Acme::Ghost::Log/facility>
=head2 group
group => 'nogroup',
group => 65534,
This attribute sets group/gid for spawned process
=head2 ident
ident => 'myDaemon',
This attribute sets ident string for system log (syslog)
=head2 logfile
logfile => '/var/log/myDaemon.log',
This attribute sets log file path. By default all log entries will be printed to syslog
See L<Acme::Ghost::Log/file>
=head2 logger
logger => Mojo::Log->new,
This attribute perfoms to set predefined logger, eg. Mojo::Log.
If you set this attribute, the specified logger will be used as the preferred logger
=head2 loghandle
Log filehandle, defaults to opening "file" or uses syslog if file not specified
See L<Acme::Ghost::Log/handle>
=head2 loglevel
loglevel => 'debug',
This attribute sets the log level
See L<Acme::Ghost::Log/level>
=head2 logopt
logopt => 'ndelay,pid',
This attribute contains zero or more of the options
See L<Acme::Ghost::Log/logopt>
=head2 name
name => 'myDaemon',
This attribute sets name of daemon. Default: script name C<basename($0)>
=head2 pidfile
pidfile => '/var/run/myDaemon.pid',
This attribute sets PID file path. Default: ./<NAME>.pid
=head2 user
user => 'nobody',
user => 65534,
This attribute sets user/uid for spawned process
=head1 METHODS
This class implements the following methods
=head2 again
This method is called immediately after creating the instance and returns it
B<NOTE:> Internal use only for subclasses!
=head2 daemonize
$g = $g->daemonize;
Main routine for just daemonize.
This routine will check on the pid file, safely fork, create the pid file (storing the pid in the file),
become another user and group, close STDIN, STDOUT and STDERR, separate from the process group (become session leader),
and install $SIG{INT} to remove the pid file. In otherwords - daemonize.
All errors result in a die
=head2 filepid
my $filepid = $g->filepid;
This method returns L<Acme::Ghost::FilePid> object
=head2 flush
$self = $self->flush;
This internal method flush (resets) process counters to defaults. Please do not use this method in your inherits
=head2 is_daemonized
$g->is_daemonized or die "Your ghost process really is not a daemon"
This method returns status of daemon:
True - the process is an daemon;
False - the process is not daemon;
=head2 is_spirited
my $is_spirited = $g->is_spirited;
This method returns status of spirit:
True - the process is an spirit;
False - the process is not spirit;
=head2 log
my $log = $g->log;
This method returns L<Acme::Ghost::Log> object
=head2 ok
$g->ok or die "Interrupted!";
This method checks process state and returns boolean status of healthy.
If this status is false, then it is immediately to shut down Your process
as soon as possible, otherwise your process will be forcibly destroyed
within 7 seconds from the moment your process receives the corresponding signal
=head2 pid
print $g->pid;
This method returns PID of the daemon
=head2 set_gid
$g = $g->set_gid('1000 10001 10002');
$g = $g->set_gid(1000);
$g = $g->set_gid('nogroup');
$g = $g->set_gid;
Become another group. Arguments are groups (or group ids or space delimited list of group ids). All errors die
=head2 set_uid
$g = $g->set_uid(1000);
$g = $g->set_uid('nobody');
$g = $g->set_uid;
Become another user. Argument is user (or userid). All errors die
=head1 CONTROL METHODS
List of LSB Daemon Control Methods
These methods can be used to control the daemon behavior.
Every effort has been made to have these methods DWIM (Do What I Mean),
so that you can focus on just writing the code for your daemon.
=head2 ctrl
exit $g->ctrl( shift @ARGV, 'USR2' );
# start, stop, restart, reload, status
Daemon Control Dispatcher with using USR2 to reloading
exit $g->ctrl( shift @ARGV, 0 );
This example shows how to forced suppress reloading (disable send users signals to daemon)
=head2 reload
$exit_code = $g->reload; # SIGHUP (by default)
$exit_code = $g->reload('USR2'); # SIGUSR2
$exit_code = $g->reload(12); # SIGUSR2 too
say "Reloading ". $g->pid;
This method performs sending signal to Your daemon and return C<0> as exit code.
This method is primarily intended to perform a daemon reload
=head2 restart
$exit_code = $g->restart;
if ($exit_code) {
say STDERR "Restart failed " . $g->pid;
} else {
say "Restart successful";
}
This method performs restarting the daemon and returns C<0> as successfully
exit code or C<1> in otherwise
=head2 start
my $exit_code = $g->start;
say "Running ". $g->pid;
exit $exit_code;
This method performs starting the daemon and returns C<0> as exit code.
The spawned process calls the startup handler and exits with status C<0>
as exit code without anything return
=head2 status
if (my $runned = $g->status) {
say "Running $runned";
} else {
say "Not running";
}
This method checks the status of running daemon and returns its PID (alive).
The method returns 0 if it is not running (dead).
=head2 stop
if (my $runned = $g->stop) {
if ($runned < 0) {
die "Daemon " . $g->pid ." is still running";
} else {
say "Stopped $runned";
}
} else {
say "Not running";
}
This method performs stopping the daemon and returns:
+PID -- daemon stopped successfully
0 -- daemon is not running
-PID -- daemon is still running, stop failed
=head1 HOOKS
lib/Acme/Ghost.pm view on Meta::CPAN
my $recur = $loop->recurring(1 => sub {
my $l = shift; # loop
$l->stop unless $self->ok;
$self->log->info("Tick! " . ++$i);
$l->stop if $i >= 10;
});
$self->log->debug("Start IOLoop");
# Start event loop if necessary
$loop->start unless $loop->is_running;
$self->log->debug("Finish IOLoop");
}
1;
=item ghost_ae.pl
AnyEvent example
my $g = MyGhost->new(
logfile => 'daemon.log',
pidfile => 'daemon.pid',
);
exit $g->ctrl(shift(@ARGV) // 'start', 0); # start, stop, restart, reload, status
1;
package MyGhost;
use parent 'Acme::Ghost';
use AnyEvent;
sub startup {
my $self = shift;
my $quit = AnyEvent->condvar;
my $i = 0;
# Create watcher timer
my $watcher = AnyEvent->timer (after => 1, interval => 1, cb => sub {
$quit->send unless $self->ok;
});
# Create process timer
my $timer = AnyEvent->timer(after => 3, interval => 3, cb => sub {
$self->log->info("Tick! " . ++$i);
$quit->send if $i >= 10;
});
$self->log->debug("Start AnyEvent");
$quit->recv; # Run!
$self->log->debug("Finish AnyEvent");
}
1;
=item ghost_nobody.pl
This example shows how to start daemons over nobody user and logging to syslog (default)
my $g = MyGhost->new(
pidfile => '/tmp/daemon.pid',
user => 'nobody',
group => 'nogroup',
);
exit $g->ctrl(shift(@ARGV) // 'start', 0); # start, stop, restart, status
1;
package MyGhost;
use parent 'Acme::Ghost';
sub startup {
my $self = shift;
my $max = 100;
my $i = 0;
while ($self->ok) {
$i++;
sleep 3;
$self->log->debug(sprintf("> %d/%d", $i, $max));
last if $i >= $max;
}
}
1;
=back
=head1 DEBUGGING
You can set the C<ACME_GHOST_DEBUG> environment variable to get some advanced diagnostics information printed to
C<STDERR>.
ACME_GHOST_DEBUG=1
=head1 TO DO
See C<TODO> file
=head1 SEE ALSO
L<CTK::Daemon>, L<Net::Server::Daemonize>, L<Mojo::Server>,
L<Mojo::Server::Prefork>, L<Daemon::Daemonize>, L<MooseX::Daemonize>,
L<Proc::Daemon>
=head1 AUTHOR
Serż Minus (Sergey Lepenkov) L<https://www.serzik.com> E<lt>abalama@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright (C) 1998-2026 D&D Corporation
=head1 LICENSE
This program is distributed under the terms of the Artistic License Version 2.0
( run in 1.385 second using v1.01-cache-2.11-cpan-63c85eba8c4 )