【问题标题】:Running python script with cron only if not running仅在未运行时使用 cron 运行 python 脚本
【发布时间】:2011-09-03 01:01:15
【问题描述】:

我需要每分钟运行一个 python 脚本 (job.py)。如果该脚本已在运行,则不得启动它。它的执行时间可能在 10 秒到几个小时之间。

所以我放入了我的 crontab:

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

为了避免在脚本已经运行时启动它,我使用了flock()。

这是脚本(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 ()

这种方法似乎有效。

我有什么遗漏吗?使用这种方法会遇到什么麻烦吗?

是否有更多建议或“适当”的方式来实现这种行为?

感谢您的任何建议。

【问题讨论】:

    标签: python cron flock


    【解决方案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】:

      当机器重新启动或在脚本运行时冻结(因此是活动锁定)时,您会遇到麻烦。解决这个问题的简单方法是使用@reboot cron 时间戳来运行rm /path/to/lock

      【讨论】:

      • 非常感谢。我会考虑到这一点。文件锁定是否通过重新启动持续存在?这取决于我使用的文件系统(实际上是 ext4)?
      • 文件锁定在重新启动后不会持续存在。它们甚至不会在重新启动的进程中持久存在,这就是为什么您不必释放代码中的锁 - 它会在进程终止时释放。
      • @Jean-Paul 这意味着我不用担心 Mel 所说的重启和死机?
      【解决方案3】:

      上周我遇到了这个确切的问题,虽然我确实找到了一些好的解决方案,但我决定制作一个非常简单干净的python包并将其上传到PyPI。

      安装:pip install quicklock

      使用起来极其简单:

      [nate@Nates-MacBook-Pro-3 ~/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's create a lock so that only one instance of a script will run
      ...
      >>> singleton('hello world')
      >>>
      >>> # Let's 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
      [nate@Nates-MacBook-Pro-3 ~/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,它是一个守护进程,它将在前一个实例完成后 x 秒重新启动脚本,因此您永远不会有相同脚本的重叠实例。

        如果满足特定条件,您甚至可以调整它以在之后立即启动实例。

        (恐怕网站有点基础,但该项目很稳定,并且在我所知道的最后几个网站上运行。一旦我推出 v0.0.3,我将制作一个漂亮、漂亮的网站!)

        【讨论】:

        • 感谢您的意见。但我认为使用你的代码有点像用大炮射击鸟,因为它带来了比我实际需要的更多的功能(并行执行等)。
        猜你喜欢
        • 2015-05-15
        • 2016-10-24
        • 2014-11-20
        • 2011-05-26
        • 2011-05-28
        • 2015-03-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多