19

我需要每分钟运行一个 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 ()

这种方法似乎有效。

有什么我想念的吗?使用这种方法会遇到什么麻烦吗?

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

我感谢你的任何建议。

4

4 回答 4

13

我会提出的唯一建议是让您的异常处理更加具体。您不希望fcntl有一天意外删除导入并隐藏该NameError结果。始终尝试捕获您要处理的最具体的异常。在这种情况下,我建议如下:

import errno

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

这样,任何其他导致无法获得锁的原因都会出现(可能在您的电子邮件中,因为您使用的是 cron),您可以决定是否需要管理员查看、程序处理的其他情况或其他情况.

于 2011-05-27T01:28:19.333 回答
3

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

于 2011-05-27T00:30:12.033 回答
2

上周我遇到了这个确切的问题,虽然我确实找到了一些好的解决方案,但我决定制作一个非常简单干净的 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

于 2015-01-28T06:48:04.380 回答
0

您可以使用Fat Controller,它是一个守护进程,它将在前一个实例完成后 x 秒重新启动脚本,因此您永远不会有相同脚本的重叠实例。

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

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

于 2011-05-30T06:59:35.953 回答