2015-06-19 68 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; 

您可能希望將發送到處理程序的信號轉發給子節點。