Сценарий Bash, чтобы сигнализировать одновременно исполняемый экземпляр (тот же скрипт) о состоянии и счетчике приращения

Задний план

Вот чего я хочу достичь. У меня есть (потенциально) долговременный процесс. Теперь у меня есть блокировка на месте просто отлично, и все в порядке.

Однако, поскольку это запланированное задание, сценарий будет выполняться снова и снова и снова. В реальном сценарии, который у меня есть, файл отслеживает количество сбоев. Когда он достигает порога, почта отправляется администратору, если исходный сценарий становится зомби или иным образом застревает. Если порог достигнут, и начальный процесс, который утверждает, что блокировка больше не живет, блокировка прерывается, и альтернативный текст отправляется администратору, информируя об этом состоянии. Все это, вероятно, не очень актуально для проблемы, но я хочу дать полную картину здесь.

Всякий раз, когда достигается порог, счетчик сбоев в файле сбрасывается и начинается оттуда. Таким образом, исходный экземпляр может или не сможет увидеть файл счетчика сбоев.

Исходный экземпляр скрипта, который удерживал блокировку, (надеюсь) закончит свою работу и завершит работу.

Вопрос

Как я могу реализовать схему, в которой «неудачные» экземпляры, которые сталкиваются с блокировкой, посылают сигнал (я пробовал SIGUSR1 ) исходному экземпляру, а исходный экземпляр отслеживает, сколько раз он «пинговал»?

Вот тестовый сценарий, который я придумал до сих пор:

 #!/usr/bin/env bash LOCKFILE=/tmp/$(basename $0).lock let COUNTER=0 function concurrent_run { let COUNTER=COUNTER+1 echo -e "\ncaught SIGUSR1 (counter = $COUNTER)" } if ( set -o noclobber; echo "$$" > "$LOCKFILE" ) 2> /dev/null; then trap 'rm -f "$LOCKFILE"; exit $?' INT TERM EXIT trap concurrent_run USR1 echo "I was first, going to sleep" sleep 100000 trap - INT TERM EXIT USR1 else LOCKPID=$(cat "$LOCKFILE") echo "Lock already held by $LOCKPID" [[ -n "$LOCKPID" ]] && kill -0 $LOCKPID && { kill -USR1 $LOCKPID; echo "... knock knock? ($LOCKPID)"; } exit 1 fi echo "End: $COUNTER" exit 0 

( sleep имитирует длительную работу, выполняемую реальным скриптом)

Я тестирую Linux, и я пробовал имя для сигнала как USR1 и SIGUSR1 , оба дают тот же результат (т. Е. Нет).

 builtin trap -l 

дал мне 10 как SIGUSR1 , поэтому я также попробовал ручную kill -10 PID на PID исходного экземпляра. К сожалению, я не могу заставить его видеть сигнал.

Что я делаю не так?


Как протестировать

Начните один экземпляр скрипта (я назвал его sigtest ):

 $ ./sigtest I was first, going to sleep 

Запустите второй экземпляр скрипта в другом терминале, окне, панели (тот же пользователь!):

 $ ./sigtest Lock already held by 15360 ... knock knock? (15360) 

Повторение …

Ожидаемый результат в первом терминале (пропуская пустые строки):

 caught SIGUSR1 (counter = 1) caught SIGUSR1 (counter = 2) caught SIGUSR1 (counter = 3) caught SIGUSR1 (counter = 4) 

Версия Bash

 $ echo $BASH_VERSION 4.1.5(1)-release 

  • Как программно отключить пользователя ssh?
  • Невозможно убить Java-процесс
  • Как убить командную строку хрома над ssh?
  • Триггер Bash до смерти
  • Лучший способ убить процессы, созданные скриптом bash?
  • Каковы эти процессы и почему я не могу их убить?
  • Я не могу убить xfwm4
  • Запрещенное ограничение обработчика сигнала процесса инициализации pid-имен
  • 2 Solutions collect form web for “Сценарий Bash, чтобы сигнализировать одновременно исполняемый экземпляр (тот же скрипт) о состоянии и счетчике приращения”

    человек bash:

    Если bash ожидает завершения команды и получает сигнал, для которого установлена ​​ловушка, ловушка не будет выполняться до тех пор, пока команда не завершится. Когда bash ожидает асинхронную команду через встроенный wait, прием сигнала, для которого была установлен ловушка, заставит wait builtin немедленно возвращаться с статусом выхода более 128, сразу после которого выполняется ловушка.

    Заставьте его sleep 100 и дождитесь его завершения. Однако я не знаю, обрабатываются ли несколько сигналов несколько раз.

    Вы можете сообщить счетчик в долгосрочную работу двумя основными способами:

    1. Общий счетчик, защищенный второй блокировкой; или
    2. Коллекция неразделенных счетчиков, которые агрегируются по длительной работе.

    Общий счетчик достаточно прост:

     if (set -o noclobber; echo $$ > /tmp/grumpy-waiters.lock); then echo >> /tmp/grumpy-waiters rm -f /tmp/grumpy-waiters.lock fi 

    Долгосрочная работа может затем прочитать счетчик следующим образом:

     num_grumpy_waiters=0 if [ -s /tmp/grumpy-waiters ]; then num_grumpy_waiters=$(wc -c < /tmp/grumpy-waiters) fi 

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

     grumpy_shard=1 if [ -s /tmp/grumpy.${LOCKPID}.$$ ]; then grumpy_shard=$(expr $(cat /tmp/grumpy.${LOCKPID}.$$) + 1) fi echo ${grumpy_shard} > /tmp/grumpy.${LOCKPID}.$$ 

    Длительный экземпляр может подбирать эти счетчики и группировать их сразу же после освобождения главного замка:

     num_grumpy_waiters=$(cat /tmp/grumpy.$$.* 2>/dev/null | awk 'BEGIN{s=0}NF>0{s=s+int($1)}END{print s}') rm -f /tmp/grumpy.$$.* 2>/dev/null 

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

    Linux и Unix - лучшая ОС в мире.