Блокировка выполнения скрипта

Существуют разные подходы. Обычно используется файл, в котором пишется PID процесса, но это «внутренняя» блокировка, программа сама себя блокирует, зная свой PID. Но существуют и другие подходы для внешней блокировки вызываемой программы, если программа сама не умеет блокироваться.

lockfile

Типовое использование:

#!/bin/bash

lockfile -r 0 /tmp/the.lock || exit 1
# Что-то тут делаем, что надо сделать
rm -f /tmp/the.lock

Сразу возникает вопрос что будет, если скрипт перед удалением файла прервётся, например сервер выключится.

flock

flock /tmp/lalala find /

Тот же вопрос — что если работа flock прервётся.

Solo

solo не имеет этого недостатка (зато имеет другие, естественно).

timkay.com/solo/ — скрипт на Perl, блокирующий параллельный запуск программы. Для блокировки используется открытие указанного TCP порта на 127.0.0.1 . Переделанная версия ещё и ждёт -wait секунд для повторных попыток запустить программу:

#!/usr/bin/perl -s --
#
# solo v1.7
# Prevents multiple cron instances from running simultaneously.
#
# Copyright 2007-2016 Timothy Kay
# http://timkay.com/solo/
#
# It is free software; you can redistribute it and/or modify it under the terms of either:
#
# a) the GNU General Public License as published by the Free Software Foundation;
#    either version 1 (http://dev.perl.org/licenses/gpl1.html), or (at your option)
#    any later version (http://www.fsf.org/licenses/licenses.html#GNUGPL), or
#
# b) the "Artistic License" (http://dev.perl.org/licenses/artistic.html), or
#
# c) the MIT License (http://opensource.org/licenses/MIT)
#

use Socket;

alarm $timeout                                                          if $timeout;

$port =~ /^\d+$/ or $noport                                             or die "Usage: $0 -port=PORT [-wait=120] COM
$wait =~ /^\d+$/ or $nowait                                             ;
$wait = 1 unless $wait;

if ($port)
{
    # To work with OpenBSD: change to
    # $addr = pack(CnC, 127, 0, 1);
    # but make sure to use different ports across different users.
    # (Thanks to  www.gotati.com .)
    $addr = pack(CnC, 127, $<, 1);
    print "solo: bind ", join(".", unpack(C4, $addr)), ":$port\n"       if $verbose;

    $^F = 10;                   # unset close-on-exec
    $|=1;
    my $ok;
    foreach my $t(1..$wait){
        eval {
            socket(SOLO, PF_INET, SOCK_STREAM, getprotobyname('tcp'))           or die "socket: $!";
            bind(SOLO, sockaddr_in($port, $addr))                               or $silent? exit: die "solo($port): 
            $ok=1;
        };
        last if $ok;
        die("Timeout") if $t == $wait;
        if($@){
            print STDERR '.';
            sleep 1;
        }
    }
}

sleep $sleep if $sleep;

exec @ARGV;

Leave a Reply