Предотвращение состояния гонки при создании файла блокировки - PullRequest
0 голосов
/ 11 сентября 2018

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

Очень распространенный подход к блокировке - это что-то вроде этого :

function setupLockFile() {
  if (set -o noclobber; echo "lock" > "$lockfile") 2>/dev/null; then
    trap "rm -f $lockfile; exit $?" INT TERM EXIT
  else
    echo "Script running... exiting!" 
    exit 1
  fi
}

Однако естьусловие гонки - if создает файл, если он не существует, и сценарий может быть прерван до определения trap.Тогда файл блокировки не будет удален.

Так что безопасный способ сделать это?

Ответы [ 3 ]

0 голосов
/ 11 сентября 2018

Сначала проверьте файл блокировки, затем перехватите, затем напишите в него:

function setupLockFile() {
  if [ -f "$lockfile" ]; then
    echo "Script running... exiting!" 
    exit 1
  else trap "rm -f $lockfile; exit $?" INT TERM EXIT
       set -o noclobber; echo "lock" > "$lockfile" || exit 1
  fi
}

И есть "официальный" способ проверки файлов блокировки с помощью команды flock , которая является частью util-linux.

0 голосов
/ 11 сентября 2018

Давайте попробуем другой подход:

  • установить ловушку перед созданием файла блокировки
  • сохранить PID в файле блокировки
  • сделать ловушку, если PID текущего экземпляра совпадает с тем, что находится в файле блокировки

Например:

trap "cleanUp" INT TERM EXIT

function cleanUp {
  if [[ $$ -eq $(<$lockfile) ]]; then
    rm -f $lockfile
    exit $?
  fi
}

function setupLockFile {
  if ! (set -o noclobber; echo "$$" > "$lockfile") 2>/dev/null; then
    echo "Script running... exiting!"
    exit 1
  fi
}

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

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

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

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

0 голосов
/ 11 сентября 2018

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

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

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

Мой совет - либо сохранить файл блокировки во временной файловой системе (/var/run обычно представляет собой tmpfs, позволяющий pid-файлам безопасно исчезнуть при перезагрузке), чтобы все исправилось после перезагрузки, либо чтобы скрипт поднял руки и попросить ручного вмешательства. Обработка каждого случая отказа надежно увеличивает сложность и, следовательно, вероятно, увеличивает вероятность отказа, чем обращение к человеку за помощью.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...