2010-11-04 136 views
0

我有一個數據密集的Python腳本,它使用HTTP連接下載數據。我通常在一夜之間運行它。有時連接將失敗,或者網站暫時不可用。我有基本的錯誤處理,捕獲這些異常並定期再次嘗試,5分鐘後重試正常退出(並記錄錯誤)。如何監視「卡住」的Python腳本?

不過,我已經注意到,有時工作只是凍結。沒有錯誤發生,並且作業仍在運行,有時在最後一次打印消息之後數小時。

什麼是最好的辦法:

  • 顯示器 Python腳本,
  • 檢測,如果它是一個給定的時間間隔後反應遲鈍,
  • 退出它,如果它是反應遲鈍,
  • 開始另一個呢?

UPDATE

感謝大家的幫助。作爲少數的你已經指出的那樣,的urllib插座模塊沒有正確設置超時。我使用Python 2.5的遊離鹼urllib2的模塊,並捕捉和處理MetawebErrorsurllib2.URLErrors。以下是最後一個腳本掛起12小時後的錯誤輸出示例:

File "/home/matthew/dev/projects/myapp_module/project/app/myapp/contrib/freebase/api/session.py", line 369, in _httpreq_json 
    resp, body = self._httpreq(*args, **kws) 
    File "/home/matthew/dev/projects/myapp_module/project/app/myapp/contrib/freebase/api/session.py", line 355, in _httpreq 
    return self._http_request(url, method, body, headers) 
    File "/home/matthew/dev/projects/myapp_module/project/app/myapp/contrib/freebase/api/httpclients.py", line 33, in __call__ 
    resp = self.opener.open(req) 
    File "/usr/lib/python2.5/urllib2.py", line 381, in open 
    response = self._open(req, data) 
    File "/usr/lib/python2.5/urllib2.py", line 399, in _open 
    '_open', req) 
    File "/usr/lib/python2.5/urllib2.py", line 360, in _call_chain 
    result = func(*args) 
    File "/usr/lib/python2.5/urllib2.py", line 1107, in http_open 
    return self.do_open(httplib.HTTPConnection, req) 
    File "/usr/lib/python2.5/urllib2.py", line 1080, in do_open 
    r = h.getresponse() 
    File "/usr/lib/python2.5/httplib.py", line 928, in getresponse 
    response.begin() 
    File "/usr/lib/python2.5/httplib.py", line 385, in begin 
    version, status, reason = self._read_status() 
    File "/usr/lib/python2.5/httplib.py", line 343, in _read_status 
    line = self.fp.readline() 
    File "/usr/lib/python2.5/socket.py", line 372, in readline 
    data = recv(1) 
KeyboardInterrupt 

您會注意到底部的套接字錯誤。由於我使用Python 2.5的,並沒有進入到第三urllib2.urlopen選項,有另一種方式來監視,趕上這個錯誤?例如,我正在捕捉URLErrrors - urllib2套接字是否有另一種類型的錯誤,我可以捕獲哪些可以幫助我?

+1

您的http請求是否超時?像urllib這樣的模塊的基本功能沒有它們。 – 2010-11-04 02:14:06

+2

請參閱我的更新,瞭解如何在套接字模塊中設置默認超時。請注意,缺省超時並不是套接字模塊中的缺陷,因爲強加任意超時會中斷需要很長時間的有效套接字操作,如大文件傳輸。 – twneale 2010-11-05 16:25:27

+0

我已經添加了您建議的邏輯,並且今晚將嘗試另一次運行。如果這不起作用,我會嘗試修改腳本以使用Python2.6來獲取默認超時。 – 2010-11-06 17:11:59

回答

4

由於該程序正在進行網絡通信,因此我會啓動一個像Charles http://www.charlesproxy.com/這樣的調試代理,並查看腳本和服務器之間來回發生了什麼奇怪的事情。

另外考慮到套接字模塊默認沒有超時設置,因此可能會掛起。但是,從python 2.6開始,您可以將第三個參數傳遞給urllib2.urlopen(如果使用的是urllib2,那就是),指定一個請求超時時間(秒)。這樣腳本就會出錯,而不是從一個可能不合作的服務器的響應中等待。如果你還沒有,那麼在嘗試任何更詳細的事情之前,我會先檢查這些事情。

更新蟒蛇2.5: 在Python < 2.6做到這一點,你就必須直接在插座模塊,它使用的urllib2在設定的超時值。我沒有嘗試過,但大概是有效的。發現此信息在http://www.voidspace.org.uk/python/articles/urllib2.shtml

import socket 
import urllib2 

# timeout in seconds 
timeout = 10 
socket.setdefaulttimeout(timeout) 

# this call to urllib2.urlopen now uses the default timeout 
# we have set in the socket module 
req = urllib2.Request('http://www.voidspace.org.uk') 
response = urllib2.urlopen(req) 
+0

我使用Python 2.5,不幸的是(我已經在更新的問題中複製了我的結果)。 2.5還有另一種方法來達到這個目的嗎? – 2010-11-05 11:42:29

1

一個簡單的方法,你問什麼是利用由當前的程序發送到監控輸出另一個收穫計劃的UDP數據包。如果它不能在一定的時間內接收數據包,它殺死那麼其他Python進程重新啓動另外一個

+0

程序爲什麼要發送UDP數據包? – nmichaels 2010-11-04 01:43:03

+0

也可以簡單地用一個時間戳更新一個類似pid的文件,並且有一個看護者檢查時間是否被合理地更新。如果程序確實是鎖定的,則可以在另一個線程中更新時間戳,而不需要對當前代碼進行任何實際的修改。如果在程序鎖定後發現時間戳仍在更新,那麼只有線程鎖定,並且答案是使用該另一個線程來執行監視。 – 2010-11-04 01:45:54

+0

作爲一種跟蹤其運行與否的方法。如果它鎖定,您的當前進程將停止發送UDP數據包,並且將使其易於追蹤。 @Zack,你不會想在線程中完成它,而是在單獨的進程中完成。只是使用線程真的不會工作瓦特/ python,因爲線程都被Python詮釋器鎖定,如果他們從一個進程運行 – g19fanatic 2010-11-04 01:56:51

6

這聽起來像有在腳本中的錯誤。答案不在於監視錯誤,而在於追捕錯誤並修復錯誤。

我們無法幫助您在沒有看到某些代碼的情況下查找錯誤。但作爲一個普遍的想法,您可能想要使用日誌記錄來查明問題發生的位置,並編寫unit tests以幫助您建立有關代碼中哪些部分沒有錯誤的信心。

另一個想法是用Ctrl-C打破你的「卡住」程序並研究追蹤信息。它會告訴你你的程序最後執行的是哪一行。 這可能會給你一個線索腳本出錯的線索。

+0

我打斷了最新的運行並更新了我的問題與結果。 – 2010-11-05 11:41:03

+0

@Wraith:我認爲twneale的建議是很好的嘗試。另外,如果你向同一臺服務器發出很多請求,你可能需要嘗試在請求之間放置一個'time.sleep(...)'命令,這樣你就不會太費勁地打到服務器。有些服務器阻止來自過分苛刻客戶的請求。 – unutbu 2010-11-05 16:50:25

1

您可以在pdb中運行腳本,並在您懷疑它被凍結時插入。它不會自行工作,但可能會幫助您找出凍結的原因。