简体   繁体   English

仅在未运行时使用 cron 运行 python 脚本

[英]Running python script with cron only if not running

I need to run a python script (job.py) every minute.我需要每分钟运行一个 python 脚本(job.py)。 This script must not be started if it is already running.如果该脚本已在运行,则不得启动它。 Its execution time can be between 10 seconds and several hours.它的执行时间可以在 10 秒到几个小时之间。

So I put into my crontab:所以我把我的 crontab :

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

To avoid starting the script when it is already running, I use flock().为了避免在脚本已经运行时启动它,我使用了flock()。

This is the script (job.py):这是脚本(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 ()

This approach seems to work.这种方法似乎有效。

Is there anything I am missing?有什么我想念的吗? Are there any troubles I can run into using this approach?使用这种方法会遇到什么麻烦吗?

Are there more advised or "proper" ways of achieving this behaviour?是否有更多建议或“适当”的方式来实现这种行为?

I thank you for any suggestion.我感谢你的任何建议。

The only suggestion I would make is to make your exception handling a little more specific.我会提出的唯一建议是让您的异常处理更加具体。 You don't want to accidentally delete the fcntl import one day and hide the NameError that results.您不希望有一天意外删除fcntl导入并隐藏导致的NameError Always try to catch the most specific exception you want to handle.始终尝试捕获您要处理的最具体的异常。 In this case, I suggest something like:在这种情况下,我建议如下:

import errno

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

This way, any other cause of the lock being unobtainable shows up (probably in your email since you're using cron) and you can decide if it's something for an administrator to look at, another case for the program to handle, or something else.这样,任何其他导致无法获得锁的原因都会出现(可能在您的 email 中,因为您使用的是 cron),您可以决定是否需要管理员查看、程序处理的另一种情况或其他情况.

I ran into this exact problem last week, and although I did find some good solutions, I decided to make a very simple and clean python package and uploaded it to PyPI.上周我遇到了这个确切的问题,虽然我确实找到了一些好的解决方案,但我决定制作一个非常简单干净的 python package 并将其上传到 PyPI。

Install with: pip install quicklock安装方式: pip install quicklock

Using it is extremely simple:使用它非常简单:

[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'!

Take a look: https://pypi.python.org/pypi/quicklock看看: https://pypi.python.org/pypi/quicklock

You're in trouble when the machine reboots or freezes with the script running (and thus an active lock).当机器重新启动或在脚本运行时冻结(因此是活动锁定)时,您会遇到麻烦。 Simple way to counter this is to use the @reboot cron timestamp to run rm /path/to/lock .解决这个问题的简单方法是使用@reboot cron 时间戳来运行rm /path/to/lock

You can use The Fat Controller which is a daemon that will restart a script x seconds after the previous instance finished, so you can never have overlapping instances of the same script.您可以使用Fat Controller ,它是一个守护进程,将在前一个实例完成后 x 秒重新启动脚本,因此您永远不会有相同脚本的重叠实例。

You can even tune it to start an instance immediately afterwards if a certain condition is met.如果满足特定条件,您甚至可以调整它以在之后立即启动实例。

(I'm afraid the website is a bit basic, but the project is stable and is running on at last several websites that I know of. I will make a nice, pretty website once I get v0.0.3 out the door!) (我担心这个网站有点基础,但这个项目很稳定,并且在我知道的最后几个网站上运行。一旦我推出 v0.0.3,我会做一个漂亮、漂亮的网站!)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM