2015-06-19 66 views
0

我有一个perl scipt,我需要它在Linux机器上每隔两小时结束一次。我打算做一个单独的脚本,并将其添加到cron.d来完成此操作,但我想要一个更简单的方法。它必须做一个优雅的退出,因为在做一个CTRL + C之后,它会写入一个日志文件并且杀死它不会写入文件。每2小时自动退出perl脚本

+0

你不需要写一个脚本来杀死一个进程:'pkill -f [pattern]'(这个发送'SIGTERM',但是你可以指定你喜欢的任何信号)。不过,我很好奇,为什么你的脚本一次只运行几个小时? – ThisSuitIsBlackNot

+0

该脚本为呼叫质量测试生成随机VOIP呼叫 – EnigmaRenegade

回答

-2

您可以通过在$SIG{INT}设置子程序赶按Ctrl-C发送的信号:

$ perl -e '$SIG{INT} = sub { print "Caught signal, cleaning up\n"; exit 0 }; while(1) {}' 

子内做你清理和你去那里。

+1

听起来好像脚本已经捕获到了SIGINT(因此它为什么会在Ctrl-C上写入日志)。问题是如何从外部杀死脚本。 –

+0

@AndrewMedico - 不,我不认为这是真的。这个问题说(强调增加)“它必须做一个优雅的退出,因为在做一个CTRL + C之后,它会写入一个日志文件并且_killing它不会写入file_。”这意味着我没有信号处理程序。如果有的话,当信号被捕获时关闭文件句柄或者(如果你想稍微马虎一点)冲洗缓冲区就会很简单。 – frezik

3

您可以设置在脚本的开始报警,并为它提供一个处理程序:

alarm 60 * 60 * 2; 
local $SIG{ALRM} = sub { 
    warn "Time over!\n"; 
    # Do the logging here... 
    exit 
}; 

的问题是,你如何会再次重新启动脚本。

+0

对于重新启动脚本,我希望这是cron.d能够做到的地方 – EnigmaRenegade

+0

@EnigmaRenegade:您仍然应该验证脚本是否过早结束或根本不会停止。 – choroba

+0

有没有一种方法可以制作单独的脚本来做到这一点? – EnigmaRenegade

1

包装保持简单。

#!/usr/bin/perl 

# usage: 
# restarter program [arg [...]] 

use strict; 
use warnings; 

use IPC::Open3 qw(open3); 
use POSIX  qw(WNOHANG); 


use constant RESTART_AFTER => 2*60*60; 
use constant KILL_INT_WAIT => 30; 
use constant KILL_TERM_WAIT => 30; 
use constant WAIT_POLL  => 15; 


sub start_it { 
    open(local *NULL, '<', '/dev/null') 
     or die($!); 

    return open3('<&NULL', '>&STDOUT', '>&STDERR', @_); 
} 


sub wait_for_it { 
    my ($pid, $max_wait) = @_; 

    my $end_time = time + $max_wait; 

    while (1) { 
     if (waitpid($pid, WNOHANG) > 0) { 
     return 1; 
     } 

     my $time = time; 
     if ($end_time >= $time) { 
     return 0; 
     } 

     sleep(1); 
    } 
} 


sub end_it { 
    my ($pid) = @_; 
    kill(INT => $pid) 
     or die($!); 

    return if wait_for_it($pid, KILL_INT_WAIT); 

    kill(TERM => $pid) 
     or die($!); 

    return if wait_for_it($pid, KILL_TERM_WAIT); 

    kill(KILL => $pid) 
     or die($!); 

    waitpid($pid, 0); 
} 


sub run_it { 
    my $end_time = time + RESTART_AFTER; 

    my $pid = start_it(@_); 

    while (1) { 
     if (waitpid($pid, WNOHANG) > 0) { 
     last; 
     } 

     my $time = time; 
     if ($end_time >= $time) { 
     end_it($pid); 
     last; 
     } 

     my $sleep_time = $end_time - $time; 
     $sleep_time = WAIT_POLL if $sleep_time > WAIT_POLL; # Workaround for race condition. 
     sleep($sleep_time); 
    } 

    my $status = $?; 

    if ($? & 0x7F) { warn("Child killed by signal ".($? & 0x7F)."\n"); } 
    elsif ($? >> 8) { warn("Child exited with error ".($? >> 8)."\n"); } 
    else    { warn("Child exited with succcesfully.\n"); } 
} 


run_it(@ARGV) while 1; 

您可能希望将发送到处理程序的信号转发给子节点。