NAME

CTK::Daemon - Abstract class to implement Daemons

VERSION

Version 1.06

SYNOPSIS

use base qw/CTK::Daemon/;

sub new {
    my $class = shift;
    # ... your code ...
    $class->SUPER::new(shift, @_);
}

sub run {
    my $self = shift;
    my $logger = $self->logger;
    $logger->log_info("Code is running");

    my $step = 5;
    while ($self->ok) { # Check it every time

        # If occurred usual error:
        #    $logger->log_error("...");
        #    mysleep SLEEP;
        #    next;

        # If occurred exception error
        #    $logger->log_crit("...");
        #    $self->exception(1);
        #    last;

        # For skip this loop
        #    $self->skip(1);
        #    next;

        last unless $self->ok; # Check it every time (after loop too)
    } continue {
        CTK::Daemon::mysleep $step if $step; # Delay! For avoid fast restarts
    }

    return 1;
}

DESCRIPTION

Abstract class to implement Daemons

FEATURES

  • Write PID file /var/run/$name.pid to make sure only one instance is running.

  • Correctly daemonize (redirect STDIN/STDOUT)

  • Restart by stop/start, exec, or signal HUP

  • Daemon restart on error

  • Handle worker processes

  • Run as different user using setuid/setgid

METHODS

new
my $daemon = CTK::Daemon->new('testdaemon', (
    ctk         => CTK::App->new(...), # Or create CTKx instance first
    debug       => 1, # Default: 0
    loglevel    => "debug", # Default: undef
    forks       => 3, # Default: 1
    uid         => "username", # Default: undef
    gid         => "groupname", # Default: undef
    saferun     => 0, # Set to 1 to enable safe mode for the run method calling
));

Daemon constructor

ctk, get_ctk
my $ctk = $daemon->get_ctk;

Returns CTK object

ctrl
exit ctrl( shift @ARGV ); # start, stop, restart, reload, status

LSB Control handler. Dispatching

logger
my $logger = $daemon->logger;

Returns logger object

logger_close
$daemon->logger_close;

Destroy logger

exit_daemon
$self->exit_daemon(0);
$self->exit_daemon(1);

Exit with status code

init, down, run, reload, cleanup

Base methods for overwriting in your class.

The init() method is called at startup - before forking

The run() method is called at inside process and describes body of the your code. This code is called at startup of each forks

The down() method is called at cleanup - after processing each forks

The reload() method is called at received HUP signal, this code is called at before running of each forks

The cleanup() method is called at before exit from main fork

start, stop, restart, status and hup

LSB methods. For internal use only

exception
$exception = $self->exception;
$self->exception(exception);

Gets/Sets exception value

hangup
$hangup = $self->hangup;
$self->hangup($hangup);

Gets/Sets hangup value

interrupt
$interrupt = $self->interrupt;
$self->interrupt($interrupt);

Gets/Sets interrupt value

skip
$skip = $self->skip;
$self->skip($skip);

Gets/Sets skip value

ok
sub run {
    my $self = shift;
    my $logger = $self->logger;
    $logger->log_info("Code is running");

    my $step = 5;
    while ($self->ok) { # Check it every time

        # If occurred usual error:
        #    $logger->log_error("...");
        #    mysleep SLEEP;
        #    next;

        # If occurred exception error
        #    $logger->log_crit("...");
        #    $self->exception(1);
        #    last;

        # For skip this loop
        #    $self->skip(1);
        #    next;

        last unless $self->ok; # Check it every time (after loop too)
    } continue {
        CTK::Daemon::mysleep $step if $step; # Delay! For avoid fast restarts
    }

    return 1;
}

Checks worker's state and allows next iteration in main loop

reinit_worker

ReInitialize worker

worker

Internal use only

mysleep
mysleep(5);

Provides safety delay

myfork
my $pid = myfork;

Provides safety forking

EXAMPLE

Classic example:

package My::App;

my $ctk = CTK::App->new;
my $daemon = My::Class->new('testdaemon', (
    ctk         => $ctk,
    debug       => 1,
    loglevel    => "debug",
    forks       => 3,
));
my $status = $daemon->ctrl("start");
$daemon->exit_daemon($status);

1;

package My::Class;

use base qw/CTK::Daemon/;

sub new {
    my $class = shift;
    # ... your code ...
    $class->SUPER::new(shift, @_);
}

sub run {
    my $self = shift;
    my $logger = $self->logger;
    $logger->log_info("Code is running");

    my $step = 5;
    while ($self->ok) { # Check it every time

        # If occurred usual error:
        #    $logger->log_error("...");
        #    mysleep SLEEP;
        #    next;

        # If occurred exception error
        #    $logger->log_crit("...");
        #    $self->exception(1);
        #    last;

        # For skip this loop
        #    $self->skip(1);
        #    next;

        last unless $self->ok; # Check it every time (after loop too)
    } continue {
        CTK::Daemon::mysleep $step if $step; # Delay! For avoid fast restarts
    }

    return 1;
}

1;

AnyEvent example (better):

package My::Class;

use base qw/CTK::Daemon/;
use AnyEvent;

sub run {
    my $self = shift;
    my $logger = $self->logger;
    my $quit_program = AnyEvent->condvar;

    # Create watcher timer
    my $watcher = AnyEvent->timer (after => 3, interval => 3, cb => sub {
        $quit_program->send unless $self->ok;
    });

    # Create process timer
    my $timer = AnyEvent->timer(after => 3, interval => 15, cb => sub {
        $quit_program->send unless $self->ok;

        $logger->log_info("[%d] Worker is running #%d", $self->{workerident}, $self->{workerpid});

    });

    # Run!
    $quit_program->recv;

    return 1;
}

1;

HISTORY

1.00 Mon Feb 27 12:33:51 2017 GMT

Init version

1.01 Mon 13 May 19:53:01 MSK 2019

Moved to CTKlib project

See Changes file

DEPENDENCIES

CTK, POSIX, Sys::Syslog, Try::Tiny

TO DO

See TODO file

BUGS

* none noted

SEE ALSO

CTK, POSIX

AUTHOR

Serż Minus (Sergey Lepenkov) https://www.serzik.com <abalama@cpan.org>

COPYRIGHT

Copyright (C) 1998-2022 D&D Corporation. All Rights Reserved

Based on PVE::Daemon ideology

LICENSE

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

See LICENSE file and https://dev.perl.org/licenses