Запуск python script с помощью cron, если он не запущен

Мне нужно каждую минуту запускать python script (job.py). Этот script не должен запускаться, если он уже запущен. Время его выполнения может составлять от 10 секунд до нескольких часов.

Итак, я положил в свой crontab:

* * * * * root cd /home/lorenzo/cron && python -u job.py 1>> /var/log/job/log 2>> /var/log/job/err

Чтобы избежать запуска script, когда он уже запущен, я использую flock().

Это script (job.py):

import fcntl
import time
import sys

def doIncrediblyImportantThings ():
    for i in range (100):
        sys.stdout.write ('[%s] %d.\n' % (time.strftime ('%c'), i) )
        time.sleep (1)

if __name__ == '__main__':
    f = open ('lock', 'w')
    try: fcntl.lockf (f, fcntl.LOCK_EX | fcntl.LOCK_NB)
    except:
        sys.stderr.write ('[%s] Script already running.\n' % time.strftime ('%c') )
        sys.exit (-1)
    doIncrediblyImportantThings ()

Этот подход, похоже, работает.

Есть ли что-нибудь, чего я не вижу? Есть ли проблемы, с которыми я могу столкнуться при использовании этого подхода?

Есть ли более рекомендуемые или "правильные" способы достижения такого поведения?

Благодарю вас за любые предложения.

Ответы

Ответ 1

Единственное, что я хотел бы сделать, это сделать вашу обработку исключений более конкретной. Вы не хотите случайно удалять импорт fcntl в один прекрасный день и скрывать результат NameError. Всегда старайтесь поймать наиболее конкретное исключение, с которым вы хотите справиться. В этом случае я предлагаю что-то вроде:

import errno

try:
    fcntl.lock(...)
except IOError, e:
    if e.errno == errno.EAGAIN:
        sys.stderr.write(...)
        sys.exit(-1)
    raise

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

Ответ 2

У вас проблемы, когда машина перезагружается или зависает при запуске script (и, следовательно, активной блокировки). Простым способом борьбы с этим является использование @reboot cron timestamp для запуска rm /path/to/lock.

Ответ 3

Я столкнулся с этой точной проблемой на прошлой неделе, и хотя я нашел несколько хороших решений, я решил сделать очень простой и чистый пакет python и загрузить его в PyPI.

Установить с помощью: pip install quicklock

Использование очень просто:

[[email protected] ~/live] python
Python 2.7.6 (default, Sep  9 2014, 15:04:36)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from quicklock import singleton
>>> # Let create a lock so that only one instance of a script will run
...
>>> singleton('hello world')
>>>
>>> # Let try to do that again, this should fail
...
>>> singleton('hello world')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/nate/live/gallery/env/lib/python2.7/site-packages/quicklock/quicklock.py", line 47, in singleton
    raise RuntimeError('Resource <{}> is currently locked by <Process {}: "{}">'.format(resource, other_process.pid, other_process.name()))
RuntimeError: Resource <hello world> is currently locked by <Process 24801: "python">
>>>
>>> # But if we quit this process, we release the lock automatically
...
>>> ^D
[[email protected] ~/live] python
Python 2.7.6 (default, Sep  9 2014, 15:04:36)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from quicklock import singleton
>>> singleton('hello world')
>>>
>>> # No exception was thrown, we own 'hello world'!

Посмотрите: https://pypi.python.org/pypi/quicklock

Ответ 4

Вы можете использовать The Fat Controller, который является демоном, который перезапустит script x секунд после завершения предыдущего экземпляра, так что вы можете никогда не имеют перекрывающихся экземпляров одного и того же script.

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

(Я боюсь, что сайт немного базовый, но проект стабилен и работает, наконец, на нескольких веб-сайтах, которые я знаю. Я сделаю красивый, красивый веб-сайт, как только я получу v0.0.3 из двери!)