1

我有一个 Perl 脚本

  • 查询数据库以获取要处理的文件列表
  • 处理文件
  • 然后退出

启动时,此脚本会创建一个文件(比如说 script.lock),并在退出时删除此文件。我有一个每分钟运行此脚本的 crontab 条目。如果锁定文件存在,则脚本退出,假设另一个自身实例正在运行。

上述过程运行良好,但我对这种方法的稳健性不太满意。具体来说,如果由于某种原因脚本过早退出并且未删除锁定文件,则新实例将无法正确执行。

我将不胜感激以下方面的建议:

  1. 使用锁定文件是一种好方法还是有更好/更健壮的方法来做到这一点?
  2. 使用 crontab 是个好主意还是我可以更好地用 sleep() 编写一个无限循环?
  3. 我应该为此使用 GNU 'daemon' 程序还是 Perl Proc::Daemon 模块(或其他等效模块)?
4

3 回答 3

4

假设您采用连续循环路线。您将程序重新调整为一个无限循环。您睡了一定时间,然后醒来并处理您的数据库文件,然后再次进入睡眠状态。

您现在需要一种机制来确保您的程序仍然正常运行。这可以通过诸如 inetd 之类的东西来完成。

但是,您的程序基本上只执行一项任务,并且一整天都在重复执行该任务。这就是 crontab 的用途。inetd机制适用于等待客户端的服务器,例如 https 或 sshd 。在这些情况下,您需要一种机制来在服务器进程死后立即重新创建它。

改进锁定文件机制的一种方法是在其中包含 PID。例如,在您的 Perl 脚本中,您可以这样做:

open my $lock_file_fh, ">", LOCK_FILE_NAME;
say {$lock_file_fh} "$$";
close $lock_file_fh;

现在,如果您的 crontab 看到锁定文件,它可以测试该进程 ID 是否仍在运行:

if [ -f $lock_file ]
then
    pid=$(cat $lock_file)
    if ! ps -p $pid
    then
        rm $lock_file
    fi
    restart_program
else
    restart_program
fi
于 2013-06-28T14:01:33.700 回答
3
  1. 如果使用 cron,则使用锁定文件是一种很好的方法,尽管如果您可以轻松安装和使用数据库,我会推荐一个数据库(MySQL/Postgres/whatever。不是 SQLite)。除其他原因外,这比本地文件系统上的文件更具可移植性,并且可以重复使用。

  2. 你确实是对的。由于您描述的原因,cron 不是这种情况的最佳主意-如果进程过早终止,则很难恢复(您可以通过检查时间戳来恢复,但不是很容易)。

    您应该使用 cron 来代替“start_if_daemon_died”作业。

  3. StackOverflow 已经很好地介绍了这一点,例如这里:

    如何在 linux 中将 Perl 脚本作为系统守护进程运行? ”或更多帖子

于 2013-06-28T13:45:00.320 回答
1

这并不是一个新的答案,而只是 David W. 接受的答案的 Perl 中的一个示例。

my $LOCKFILE = '/tmp/precache_advs.lock';

create_lockfile();
do_something_interesting();
remove_lockfile();

sub create_lockfile {
    check_lockfile();

    open my $fh, ">", $LOCKFILE or die "Unable to open $LOCKFILE: $!";
    print $fh "$$";
    close $fh;

    return;
}

sub check_lockfile {
    if ( -e $LOCKFILE ) {
        my $pid = `cat $LOCKFILE`;
        if ( system("ps -p $pid") == 0 ) {
            # script is still running, so don't start a new instance
            exit 0;
        }
        else {
            remove_lockfile();
        }
    }
    return;
}

sub remove_lockfile {
    unlink $LOCKFILE or "Unable to remove $LOCKFILE: $!";
    return;
}
于 2015-05-13T11:40:17.650 回答