2011-05-27 199 views
15

我需要每分钟运行一次python脚本(job.py)。如果脚本已经在运行,则该脚本不能启动。它的执行时间可以在10秒到几个小时之间。只有在没有运行的情况下才使用cron运行python脚本

所以我把我的crontab中:

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

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

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

这种做法似乎工作。

有什么我失踪?我可以使用这种方法遇到麻烦吗?

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

我感谢您的任何建议。

+0

大问题。 – erjoalgo 2013-06-28 04:09:12

回答

9

我唯一的建议是让你的异常处理更具体。您不希望在一天内意外删除fcntl导入,并隐藏导致结果的NameError。总是试图捕捉你想要处理的最具体的异常。在这种情况下,我建议是这样的:

import errno 

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

这样一来,任何其他原因锁定为无法获得的显示出来(可能是您的电子邮件,因为你正在使用的cron),你可以决定是否它的东西让管理员看看,程序要处理的另一个案例,或者其他的东西。

+0

谢谢。好点子。 – Hyperboreus 2011-05-27 02:34:39

2

当计算机重新启动或冻结并且脚本正在运行(因此存在主动锁定)时,您遇到了麻烦。简单的解决方法是使用@reboot cron时间戳运行rm /path/to/lock

+0

非常感谢。我会考虑这一点。文件锁是否通过重新启动持久?取决于我使用的文件系统(实际上是ext4)? – Hyperboreus 2011-05-27 00:40:43

+2

重新启动时,文件锁不是持久的。它们甚至在进程重启时不会持续存在,这就是为什么您不必在代码中释放锁的原因 - 当进程终止时它会被释放。 – 2011-05-27 01:24:29

+0

@ Jean-Paul这意味着我不担心重启和梅尔状态冻结? – Hyperboreus 2011-05-27 02:33:51

0

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

如果满足某个条件,您甚至可以调整它以便立即开始实例。我很害怕这个网站有点基本,但是这个项目很稳定,并且在我知道的最后几个网站上运行。一旦我得到了v0.0.3以外的版本,我将创建一个漂亮,漂亮的网站。门!)

+0

感谢您的意见。但是我认为使用你的代码有点像使用大炮射击鸟类,因为它带来了比我实际需要更多的功能(并行执行等)。 – Hyperboreus 2011-05-30 13:38:02

2

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

相关问题