2011-05-27 103 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

相關問題