сервис построения с Perl - это правильно


Я пытался ставить скрипт я видел вместе, плюс использовать существующий скрипт, чтобы сделать что-то запускаться как служба. Теперь у меня есть следующий скрипт, ЛП и инит.д / пуск/остановка скриптов.

Они работают, но мне интересно, если я сделал это правильно, потому что, когда я запустить службу, и я хотел бы начать его снова, он бы просто начать все заново и дать новый номер PID (это то, что я хочу? разве он не должен говорить "уже работает?") Также я не понимаю, что такое "кэш" часть stdin и stdout делает. Ни filecheck не (установил файл в начале и на последнем круге проверены на новой версии...не уверен, что это делает) вот:

#!/usr/bin/perl

#use strict;
use POSIX;
use DateTime;
use Fcntl qw(:flock);
use File::CacheDir qw(cache_dir);

Log("Initializing...");

# Find and read config file
if (@ARGV != 1) {
    print("Usage: miniserv.pl <config file>");
    die;
}

if ($ARGV[0] =~ /^([a-z]:)?\//i) {
    $config_file = $ARGV[0];
}
else {
    print("NO CORRECT CONFIG FILE SPECIFIED");
    die;
}

%config = &read_config_file($config_file);
Log("Initialized...");
Log("Loaded config file.");


my $file = $0;
my $age = -M $file;
Log("File - ".$file.", age - ".$age);



# Change dir to the server root
@roots = ( $config{'root'} );
for($i=0; defined($config{"extraroot_$i"}); $i++) {
    push(@roots, $config{"extraroot_$i"});
}
chdir($roots[0]);
Log("Changed working directory: ".$roots[0]);


Status("Daemonizing...");
my $pid = fork;
if(!defined $pid)
{
    LogError("Unable to fork : $!");
    die;
}
if($pid)
{
    Log("Parent process exiting, let the deamon (".$pid.") go...");
    sleep 3;
    exit;
}
POSIX::setsid;


if(-e $config{'pidfile'})
{
    open(PID, "<".$config{'pidfile'});
    my $runningpid = <PID>;
    close PID;
    unlink $config{'pidfile'};
    while(-e "/proc/".$runningpid)
    {
        Status("Waiting for ".$runningpid." to exit...");
        Log("Waiting for ".$runningpid." to exit...");
        sleep 1;
    }
}

open(PID, ">".$config{'pidfile'}) || die "Failed to create PID file $_[0] : $!";
print PID $$;
close PID;

Log("The deamon is now running...");
Status("Deamon running");

my $stdout = cache_dir({base_dir => $config{'root'}.'/cache', ttl => '1 day', filename => "STDOUT".$$});
my $stderr = cache_dir({base_dir => $config{'root'}.'/cache', ttl => '1 day', filename => "STDERR".$$});
Log("STDOUT : ".$stdout);
Log("STDERR : ".$stderr);
open STDIN, '/dev/null';
open STDOUT, '>>'.$stdout;
open STDERR, '>>'.$stderr;

while(1)
{
    #### Code to be performed by the daemon





    if($age - (-M $file))
    {
        Log("File modified, restarting");
        open(FILE, $file ." |");
        close(FILE);
        last;
    }
    if(!-e $config{'pidfile'})
    {
        Log("Pid file doesn't exist, time go exit.");
        last;
    }
    sleep 5;
}



sub Log
{
    my $string = shift;
    if($string)
    {
        my $time = DateTime->now();
        if(open(LOG, ">>".$config{'logfile'}))
        {
            flock(LOG, LOCK_EX);
            print LOG $$." [".$time->ymd." ".$time->hms."] - ".$string."\r\n";
            close LOG;
        }
    }
}

sub LogError
{
    my $string = shift;

    if($string)
    {
        my $time = DateTime->now();
        if(open(LOG, ">>".$config{'errorlog'}))
        {
            flock(LOG, LOCK_EX);
            print LOG $$." [".$time->ymd." ".$time->hms."] - ".$string."\r\n";
            close LOG;
        }
    }
}

sub Status
{
    my $string = shift;
    if($string)
    {
        $0 = "My Daemon- ".$string;
    }
    return $0;
}


# read_config_file(file)
# Reads the given config file, and returns a hash of values
sub read_config_file
{
    local %rv;
    if(-e $_[0]) 
    {
        open(CONF, $_[0]) || die "Failed to open config file $_[0] : $!";
        while(<CONF>) {
            s/\r|\n//g;
            if (/^#/ || !/\S/) { next; }
            /^([^=]+)=(.*)$/;
            $name = $1; $val = $2;
            $name =~ s/^\s+//g; $name =~ s/\s+$//g;
            $val =~ s/^\s+//g; $val =~ s/\s+$//g;
            $rv{$name} = $val;
            }
        close(CONF);
        return %rv;
    } else {
        print("COULD NOT FIND CONFIG FILE");
        die;
    }
}

запустить скрипт

#!/bin/sh
echo Starting reliand server in /usr/libexec/reliand
trap '' 1
LANG=
export LANG
#PERLIO=:raw
unset PERLIO
export PERLIO
PERLLIB=/usr/libexec/reliand
export PERLLIB
exec '/usr/libexec/reliand/miniserv.pl' /etc/reliand/miniserv.conf

сценария

#!/bin/sh
# chkconfig: 235 99 10
# description: Start or stop the reliand server
#
### BEGIN INIT INFO
# Provides: reliand
# Required-Start: $network $syslog
# Required-Stop: $network
# Default-Start: 2 3 5
# Default-Stop: 0 1 6
# Description: Start or stop the reliand server
### END INIT INFO

start=/etc/reliand/start
stop=/etc/reliand/stop
lockfile=/var/lock/subsys/reliand
confFile=/etc/reliand/miniserv.conf
pidFile=/var/reliand/miniserv.pid
name='reliand'

case "$1" in
'start')
    $start >/dev/null 2>&1 </dev/null
    RETVAL=$?
    if [ "$RETVAL" = "0" ]; then
        touch $lockfile >/dev/null 2>&1
    fi
    ;;
'stop')
    $stop
    RETVAL=$?
    if [ "$RETVAL" = "0" ]; then
        rm -f $lockfile
    fi
    pidfile=`grep "^pidfile=" $confFile | sed -e 's/pidfile=//g'`
    if [ "$pidfile" = "" ]; then
        pidfile=$pidFile
    fi
    rm -f $pidfile
    ;;
'status')
    pidfile=`grep "^pidfile=" $confFile | sed -e 's/pidfile=//g'`
    if [ "$pidfile" = "" ]; then
        pidfile=$pidFile
    fi
    if [ -s $pidfile ]; then
        pid=`cat $pidfile`
        kill -0 $pid >/dev/null 2>&1
        if [ "$?" = "0" ]; then
            echo "$name (pid $pid) is running"
            RETVAL=0
        else
            echo "$name is stopped"
            RETVAL=1
        fi
    else
        echo "$name is stopped"
        RETVAL=1
    fi
    ;;
'restart')
    $stop ; $start
    RETVAL=$?
    ;;
*)
    echo "Usage: $0 { start | stop | restart }"
    RETVAL=1
    ;;
esac
exit $RETVAL


293
2
задан 9 мая 2011 в 12:05 Источник Поделиться
Комментарии
1 ответ

О, черт, нет. Вы должны использовать строгие комментарии. Всегда, всегда, всегда использовать строгие и использовать предупреждения , пока вы не понимаете, когда вам может понадобиться для выборочного отключения части того, что они делают. Невыполнение этого требования будет добавить огромное количество дополнительной отладки для вашего будущего. Без них вы будете предметом непрекращающихся (и правильно) нытье каждый раз, когда вы публикуете свой код на любой форум Perl, который стоит дерьмо.

ОК, во-вторых, свой PID-файл должен помешать двум или более экземпляров работали одновременно. Логика такова:

Does the pid file exist?
No - cool, we can run.
Yes - Need more tests.
Load the PID from the pid file.
Is there a process running with the PID from the pid file?
No - cool, we can run.
Yes - uh oh, gotta abort.

Сейчас ваша логика этого не делает.

В cache_dir() материала на CPAN модуль файл::CacheDir. Похоже, он обрабатывает некоторые лог-мямлить.

Большой блок кода, который frobs поток ввода/вывода в stdout/stderr, в это открытие все стандартные ИО выход указать на некоторые autorotated файлы cache_dir.

Если это упражнение для обучения себя, как написать демон, рассмотреть значение этого Perlmonks статьи, и с помощью команды CPAN модули, такие как прок::Pid_File и материалы::Демон.

Далее, разбить свой код на подпрограммы. Любой функциональный блок кода, если это возможно, помещаются на один экран текста. Вы код должен выглядеть так:

use strict;
use warnings;
# A bunch of use statements here
use Blarg;

my %args = process_command_line(@ARGV);
my $cfg = load_config_file( %args );

daemonize($cfg);

while (1) {

do_stuff($cfg);

check_pid_file($cfg->{pid_file});

}

Все остальное в подпрограммы. Каждый как можно короче.

Помните, что ваш код будет поддерживаться маньяк-убийца с вопросами управления гневом и очень короткий промежуток внимания. Сделайте свой skimmable код, и вы можете выжить.

Наконец, не используйте два аргумента открыть с помощью глобальных дескрипторов файлов. Это считается плохой идеей на протяжении более чем десятилетия.

Например, когда вы открываете файл config, сделайте это:

my $config_file_path = shift;

open my $conf, $config_file_path
or die "Failed to open config file '$config_file_path': $!\n";

my %config;

while( my $line = <$conf> ) {
$line =~ s/\r|\n//g;

next if /^#/; # Skip comments

next unless /\S/; # Skip blank lines

next unless /^\s*([^=]+)\s*=\s*(.*)\s*$/; # Skip malformed lines.

my $name = $1;
my $val = $2;

$config{$name} = $val;
}

return \%config;

Я изменил свой цикл while, чтобы использовать явную переменную, потому что $_ не локализована автоматически при. Я также изменил свой захват, чтобы пропустить захватив лидирующие и завершающие пробелы. Специально видоизмененные строки пропуская логика для краткости.

Но настоящий ответ заключается в том, чтобы использовать модуль, как файл config::IniFiles или конфигурации::все для обработки конфигурационных файлов.

Оболочки материал выглядит довольно много стандартных и ОК.

3
ответ дан 28 мая 2011 в 04:05 Источник Поделиться