仅在未运行时使用 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 作业(linux)

仅在特定时间每分钟运行一次 cron 作业?

使用 cron 运行 python 脚本,matplotlib 错误

Azure DevOps Pipelines - 仅在上一次运行成功时运行 YAML 管道

Python 脚本在 docker 容器中找不到使用 CRON 运行的 ENV 变量