仅在未运行时使用 cron 运行 python 脚本
Posted
技术标签:
【中文标题】仅在未运行时使用 cron 运行 python 脚本【英文标题】:Running python script with cron only if not running 【发布时间】: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 ()
这种方法似乎有效。
我有什么遗漏吗?使用这种方法会遇到什么麻烦吗?
是否有更多建议或“适当”的方式来实现这种行为?
感谢您的任何建议。
【问题讨论】:
【参考方案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,我将制作一个漂亮、漂亮的网站!)
【讨论】:
感谢您的意见。但我认为使用你的代码有点像用大炮射击鸟,因为它带来了比我实际需要的更多的功能(并行执行等)。以上是关于仅在未运行时使用 cron 运行 python 脚本的主要内容,如果未能解决你的问题,请参考以下文章
本地化应用程序仅在非基本语言上崩溃,并且仅在未使用Xcode运行时崩溃
使用 cron 运行 python 脚本,matplotlib 错误