有没有办法每分钟(或2分钟、5分钟等)运行一个脚本,但前提是该脚本尚未运行?
我们有一组需要每分钟运行的脚本。有时它们可能在一秒钟内开始和结束,有时它们可能持续 5 分钟。
我们目前避免同时执行的方法是在每个脚本中设置一个is_running
标志,如果该标志仍处于启用状态,则退出。但这有点不可靠(即,致命错误会导致该标志即使在脚本停止后仍保持启用状态)。
我们可以编写自己的小管理器,但我想知道是否存在更时尚的解决方案。
答案1
更好的方法是使用flock
而不是 pidfile。检查手册页:羊群(1)优点是无论进程如何结束/死亡,锁都会随之消失。
答案2
我倾向于同意 Warner 的 pid 文件答案。但是,Anacron 的以下功能可以实现这一点吗?
-s
Serialize execution of jobs. Anacron will not start a new job before the previous one finished.
我自己还没有测试过,我发现 anacron 的文档不够详尽......
如果您想特别懒惰 ;-) 如果通过 ps 输出查找结果显示进程正在运行,则只需让脚本退出即可。但最好使用 lock/pid 文件。
答案3
这是该方法的正确解决方案。通常,将使用 pid 文件并针对该进程进行 pid 测试以确保其正在运行。如果过时,则将删除锁文件,并且进程仍将运行。
任何额外的智能通常都会被写入软件本身中,作为守护进程,而不是在 cron 中运行。
答案4
如果您的脚本在 Python 中运行,这是一个解决方案(或者您可以创建一个 Python 命令在下一个命令之前运行) - 我上周遇到了这个确切的问题,虽然我确实找到了一些好的解决方案,但我决定制作一个非常简单和干净的 Python 包并将其上传到 PyPI。您当然可以锁定,而__file__
不必考虑给它一个自定义资源名称来锁定。
安装方式: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'!