view release on metacpan or search on metacpan
lib/Acme/Ghost.pm view on Meta::CPAN
my $self = bless {
name => $name,
user => $user,
group => $group,
uid => $uid,
gid => $gid,
gids => $gids,
# PID
pidfile => $args->{pidfile} || File::Spec->catfile(getcwd(), sprintf("%s.pid", $name)),
_filepid => undef,
# Log
facility => $args->{facility},
logfile => $args->{logfile},
ident => $args->{ident} || $name,
logopt => $args->{logopt},
logger => $args->{logger},
loglevel => $args->{loglevel},
loghandle => $args->{loghandle},
_log => undef,
# Runtime
initpid => $$, # PID of root process
ppid => 0, # PID before daemonize
pid => 0, # PID daemonized process
daemonized => 0, # 0 - no daemonized; 1 - daemonized
spirited => 0, # 0 - is not spirit; 1 - is spirit (See ::Prefork)
# Manage
ok => 0, # 1 - Ok. Process is healthy (ok)
lib/Acme/Ghost.pm view on Meta::CPAN
$self->{ppid} = $$;
# Get UID & GID
my $uid = $self->{uid}; # UID
my $gids = $self->{gid}; # returns list of groups (gids)
my $gid = (split /[\s,]+/, $gids)[0]; # First GID
_debug("!! UID=%s; GID=%s; GIDs=\"%s\"", $uid, $gid, $gids);
# Pre Init Hook
$self->preinit;
$self->{_log} = undef; # Close log handlers before spawn
# Spawn
my $pid = _fork();
if ($pid) {
_debug("!! Spawned (PID=%s)", $pid);
if ($safe) { # For internal use only
$self->{pid} = $pid; # Store child PID to instance
return $self;
}
exit 0; # exit parent process
lib/Acme/Ghost/FilePid.pm view on Meta::CPAN
$fp->file("/var/run/file.pid");
my $pidfile = $fp->file;
Accessor/mutator for the filename used as the pid file.
=head2 load
$fp->load;
Load owner pid from file.
On success, the object is returned. On failure, C<undef> is
returned.
=head2 owner
$fp->owner(123);
my $owner = $fp->owner;
Accessor/mutator for the pid being saved to the pid file.
=head2 pid
lib/Acme/Ghost/FilePid.pm view on Meta::CPAN
Removes the pid file from disk. Returns true on success, false on
failure.
=head2 running
my $pid = $fp->running;
die "Service already running: $pid" if $pid;
Checks to see if the pricess identified in the pid file is still
running. If the process is still running, the pid is returned. Otherwise
C<undef> is returned.
=head2 save
$fp->save;
Writes the pid file to disk, inserting the pid inside the file.
On success, the object is returned. On failure, C<undef> is
returned.
=head1 HISTORY
See C<Changes> file
=head1 TO DO
See C<TODO> file
lib/Acme/Ghost/FilePid.pm view on Meta::CPAN
my $self = shift;
if (scalar(@_) >= 1) {
$self->{owner} = shift;
return $self;
}
return $self->{owner};
}
sub running {
my $self = shift;
my $owner = $self->load->owner || 0; # Get PID from file
my $r = kill(0, $owner) ? $owner : undef;
$self->{is_running} = $r ? 1 : 0;
return $r; # Is running?
}
sub remove {
my $self = shift;
my $file = $self->file;
return $self unless -e $file;
unlink $file;
$self->owner(0); # Set owner PID to 0
return $self;
lib/Acme/Ghost/FilePid.pm view on Meta::CPAN
sub save {
my $self = shift;
my $file = $self->file;
my $pid = $self->pid || $$;
$self->owner($pid); # Set owner PID as current PID
# Save PID to file
my $fh = IO::File->new($file, "w");
croak qq/Can't open file "$file": $!/ unless defined $fh;
$fh->write("$pid\n") or croak qq/Can't write to file "$file": $!/;
undef $fh; # automatically closes the file
# Returns self
return $self;
}
sub load {
my $self = shift;
my $file = $self->file;
return $self unless -e $file;
# Read file
my $ret = my $content = '';
my $fh = IO::File->new($file, "r");
croak qq/Can't open file "$file": $!/ unless defined $fh;
while ($ret = $fh->read(my $buf, 255)) { $content .= $buf }
croak qq/Can't read from file "$file": $!/ unless defined $ret;
undef $fh; # automatically closes the file
# Set loaded PID as owner
chomp $content;
$self->owner(($content || 0) * 1) if $content =~ /^\d+$/;
# Returns object
return $self;
}
sub DESTROY {
my $self = shift;
lib/Acme/Ghost/Log.pm view on Meta::CPAN
priority is higher or equal than the configured setting.
Default: C<debug>
See also L<Sys::Syslog/Levels>
=head2 logger
This attribute perfoms to set predefined logger, eg. Mojo::Log
Default: C<undef>
=head2 logopt
This attribute contains zero or more of the options detailed in L<Sys::Syslog/openlog>
Default: C<'ndelay,pid'>
=head1 METHODS
This class implements the following methods
lib/Acme/Ghost/Log.pm view on Meta::CPAN
$log = $log->level('debug');
Active log level, defaults to debug.
Available log levels are C<trace>, C<debug>, C<info>, C<notice>, C<warn>, C<error>,
C<fatal> (C<crit>), C<alert> and C<emerg>, in that order
=head2 logger
my $logger = $log->logger;
This method returns the logger object or undef if not exists
=head2 notice
$log->notice('Normal, but significant, condition...');
$log->notice('Ok', 'then');
Log C<notice> message
=head2 provider
lib/Acme/Ghost/Log.pm view on Meta::CPAN
);
my $ENCODING = find_encoding('UTF-8') or croak qq/Encoding "UTF-8" not found/;
sub new {
my $class = shift;
my $args = @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {};
$args->{facility} ||= Sys::Syslog::LOG_USER;
$args->{ident} ||= basename($0);
$args->{logopt} ||= LOGOPTS;
$args->{logger} ||= undef;
$args->{level} ||= 'debug';
$args->{file} ||= undef;
$args->{handle} ||= undef;
$args->{provider} = 'unknown';
# Check level
croak "Incorrect log level specified" unless exists $MAGIC{$args->{level}};
# Instance
my $self = bless {%$args}, $class;
# Open sys log socket
if ($args->{logger}) {
lib/Acme/Ghost/Log.pm view on Meta::CPAN
return 1;
}
return 0 if $self->provider ne "syslog";
my $lvl = $LOGLEVELS{$level} // Sys::Syslog::LOG_DEBUG;
Sys::Syslog::syslog($lvl, LOGFORMAT, join(SEPARATOR, @msg));
}
DESTROY {
my $self = shift;
undef $self->{handle} if $self->{file};
Sys::Syslog::closelog() unless $self->logger;
}
1;
__END__
lib/Acme/Ghost/Prefork.pm view on Meta::CPAN
sub again {
my $self = shift;
my %args = @_;
# Prefork management subsystem
$self->{pool} = {}; # pid => {...}
$self->{running} = 0; # 0 - not running; 1 - running
$self->{finished} = 0; # 1 - marker for spirits and manager stopping
$self->{gracefully_stop} = 0; # 1 - marker for gracefully stopping
$self->{reader} = undef; # Readable pipe to get messages from spirits
$self->{writer} = undef; # Writable pipe to send messages to manager
$self->{spare} = $args{spare} || SPARE;
$self->{spirits} = $args{spirits} || $args{workers} || SPIRITS;
$self->{heartbeat_interval} = $args{heartbeat_interval} || HEARTBEAT_INTERVAL;
$self->{heartbeat_timeout} = $args{heartbeat_timeout} || HEARTBEAT_TIMEOUT;
$self->{graceful_timeout} = $args{graceful_timeout} || GRACEFUL_TIMEOUT;
$self->{spirit_cb} = $args{spirit};
return $self;
}
sub startup {
lib/Acme/Ghost/Prefork.pm view on Meta::CPAN
for my $pid (keys %{$self->{pool}}) {
next unless my $w = $self->{pool}{$pid}; # Get spirit struct
# No heartbeat (graceful stop)
if (!$w->{graceful} && ($w->{time} + $interval + $hb_to <= $now)) {
$log->error("Spirit $pid has no heartbeat ($hb_to seconds), restarting");
$w->{graceful} = $now;
}
# Graceful stop with timeout
my $graceful = $w->{graceful} ||= $self->{gracefully_stop} ? $now : undef;
if ($graceful && !$w->{attempt}) {
$w->{attempt}++;
$log->info("Stopping spirit $pid gracefully ($gf_to seconds)");
kill 'QUIT', $pid or $self->_stopped($pid);
}
$w->{force} = 1 if $graceful && $graceful + $gf_to <= $now; # The conditions for a graceful stop by timeout were violated
# Normal stop
if ($w->{force} || ($self->{finished} && !$graceful)) {
$log->warn("Stopping spirit $pid immediately");