launchd startInterval меньше времени, необходимого для завершения сценария

2

Я использую launchctl для загрузки / запуска моего скрипта Python, и он работает в определенной степени. Он запускается каждые 120 секунд, но иногда мой сценарий запускается за 500 секунд, и моя теория заключается в том, что у меня запущен процесс, который перезапускает его, а не позволяет запустить первый.

Я думаю, что происходит: - запустить tester.py (примерное время tester.py завершить 400 с) - через 120 с - снова запустить tester.py и отказаться от первого

Что я хочу: чтобы закончить первый tester.py, не перезапускать его.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>BuildNotification.py</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/python</string>
        <string>/Users/xcuer/tester.py</string>
    </array>
    <key>StartInterval</key>
    <integer>120</integer>
    <key>TimeOut</key>
    <integer>7200</integer>
    <key>ExitTimeOut</key>
    <integer>7200</integer>
</dict>
</plist>
donttellunclesam
источник
Я пытаюсь придумать хорошее решение, кроме проверки сценария на наличие предыдущих вызовов и выхода ...
bmike
@bmike Я пытаюсь понять, решает ли crontab эту проблему
donttellunclesam,
1
Файл блокировки был бы традиционным решением для этой ситуации. Вы можете изменить скрипт?
Грэм Милн
@GrahamMiln Как будет работать файл блокировки для моего решения? Или есть способ, которым я мог бы написать сценарий bash, который вызывает launchctl вместо самого сценария python? Есть ли в laucnhctl способ проверить, работает ли служба в данный момент?
donttellunclesam
1
Я использовал @GrahamMiln предложенный ответ crontabи launchdрабочие места. Его тест на 4 строки в оболочке может быть очень легко написан на Python, Perl, AppleScript или любом другом языке сценариев.
дан

Ответы:

1

launchd фокусируется на запуске заданий и поддержании их выполнения, в нем нет механизма для обработки перекрывающихся заданий.

Блокировка файла

Традиционно в среде UNIX файл блокировки используется для остановки многократного запуска процессов.

Основные шаги:

  1. При запуске скрипта, если файл блокировки уже существует, остановите скрипт.
  2. При запуске скрипта, если файл блокировки не существует, создайте файл блокировки.
  3. По завершении сценария удалите файл блокировки.

В macOS создайте файл блокировки /var/tmpдля общесистемных процессов.

Пример реализации

if ! mkdir /var/tmp/myscript.lock 2>/dev/null; then
    echo "Myscript is already running." >&2
    exit 1
fi

См. Быстрый и грязный способ убедиться, что одновременно выполняется только один экземпляр сценария оболочки, и Каков наилучший способ убедиться, что запущен только один экземпляр сценария Bash? для примеров сценариев.

Потенциальные проблемы

Есть крайние случаи.

launchdхочет, чтобы задания выполнялись как минимум за n секунд до окончания . Когда сценарий найдет существующий файл блокировки, подумайте о том, чтобы поспать в течение n секунд, а затем выйти.

Что произойдет, если ваш скрипт будет убит или завершится из-за ошибки? Можете ли вы быть уверены, что файл блокировки удален?

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

В сценарии оболочки перехватите сигнал завершения и убедитесь, что файл удален.

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

Грэм Милн
источник