2011-10-11 95 views
1

我有一個簡單的python腳本,用於更新數據庫中justin.tv流的狀態。這是一個基於Django的Web應用程序。此腳本在將其移至我的生產服務器之前完美運行,但現在遇到超時或凍結問題。我已經通過添加try/except塊並使腳本重試來解決超時問題,但我仍然無法弄清楚凍結問題。Python腳本在套接字連接期間無限凍結

我知道它凍結在線streamOnline = manager.getStreamOnline(stream.name, LOG)。這與socket.timeout異常發生的地方是一樣的。然而有些時候,它永遠鎖定。我無法想象python會無限凍結的場景。這是凍結腳本的代碼。我正在鏈接下面的website.networkmanagers,以及我正在使用的oauth和justin.tv python庫。

import sys, os, socket 

LOG = False 

def updateStreamInfo(): 
    # Set necessary paths 
    honstreams = os.path.realpath(os.path.dirname(__file__) + "../../../") 
    sys.path.append(honstreams) 
    os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' 

    # Import necessary moduels 
    from website.models import Stream, StreamInfo 
    from website.networkmanagers import get_manager, \ 
             NetworkManagerReturnedErrorException 

    # Get all streams 
    streams = Stream.objects.all() 

    try: 
     # Loop through them 
     for stream in streams: 

      skipstream = False 

      print 'Checking %s...' % stream.name, 
      # Get the appropriate network manager and 
      manager = get_manager(stream.network.name) 

      # Try to get stream status up to 3 times 
      for i in xrange(3): 
       try: 
        streamOnline = manager.getStreamOnline(stream.name, LOG) 
        break 
       except socket.error as e: 
        code, message = e 

        # Retry up to 3 times 
        print 'Error: %s. Retrying...' 

      # If this stream should be skipped 
      if(skipstream): 
       print 'Can\'t connect! Skipping %s' % stream.name 
       continue 

      # Skip if status has not changed 
      if streamOnline == stream.online: 
       print 'Skipping %s because the status has not changed' % \ 
         stream.name 
       continue 

      # Save status 
      stream.online = streamOnline 
      stream.save() 

      print 'Set %s to %s' % (stream.name, streamOnline) 

    except NetworkManagerReturnedErrorException as e: 
     print 'Stopped the status update loop:', e 

if(__name__ == "__main__"): 
    if(len(sys.argv) > 1 and sys.argv[1] == "log"): 
     LOG = True 

    if(LOG): print "Logging enabled" 

    updateStreamInfo() 

networkmanagers.py
oauth.py
JtvClient.py

腳本凍結

FOO @欄的例子:/.../ honstreams/honstreams#蟒蛇網站/腳本/ updateStreamStatus。 py
正在檢查angrytestie ...正在跳過angrytestie,因爲st atus尚未更改
檢查chustream ...跳過chustream,因爲狀態沒有改變
檢查cilantrogamer ...跳過cilantrogamer,因爲狀態沒有改變
| < - 插入符就坐落在這裏閃爍無限


有趣的更新

每次它凍結時間,我送一個鍵盤中斷,這是在同一行中socket.py

[email protected]:/home/honstreams/honstreams# python website/scripts/updateStreamStatus.py 
Checking angrytestie... Skipping angrytestie because the status has not changed 
Checking chustream... Skipping chustream because the status has not changed 
^CChecking cilantrogamer... 
Traceback (most recent call last): 
    File "website/scripts/updateStreamStatus.py", line 64, in <module> 
    updateStreamInfo() 
    File "website/scripts/updateStreamStatus.py", line 31, in updateStreamInfo 
    streamOnline = manager.getStreamOnline(stream.name, LOG) 
    File "/home/honstreams/honstreams/website/networkmanagers.py", line 47, in getStreamOnline 
    return self.getChannelLive(channelName, log) 
    File "/home/honstreams/honstreams/website/networkmanagers.py", line 65, in getChannelLive 
    response = client.get('/stream/list.json?channel=%s' % channelName) 
    File "/home/honstreams/honstreams/website/JtvClient.py", line 51, in get 
    return self._send_request(request, token) 
    File "/home/honstreams/honstreams/website/JtvClient.py", line 90, in _send_request 
    return conn.getresponse() 
    File "/usr/lib/python2.6/httplib.py", line 986, in getresponse 
    response.begin() 
    File "/usr/lib/python2.6/httplib.py", line 391, in begin 
    version, status, reason = self._read_status() 
    File "/usr/lib/python2.6/httplib.py", line 349, in _read_status 
    line = self.fp.readline() 
    File "/usr/lib/python2.6/socket.py", line 397, in readline 
    data = recv(1) 
KeyboardInterrupt 

有什麼想法?

回答

0

事實證明這HTTP連接不通過超時jtvClient.py

def _get_conn(self): 
    return httplib.HTTPConnection("%s:%d" % (self.host, self.port)) 

改變最後一行

return httplib.HTTPConnection("%s:%d" % (self.host, self.port), timeout=10) 

這解決了它

0

在JtvClient.py中使用httplib來處理連接。你有沒有嘗試改變這個使用httplib2呢?

除了黑暗中的暗刺之外,我還會在這段代碼中添加大量的日誌語句,以便跟蹤實際發生的情況以及它卡住的位置。然後我會確定它被卡住的地方可能會在套接字上超時(通常涉及monkeypatching或分支代碼庫),以致於東西失敗而不是掛起。

你說:

我知道它凍結上線streamOnline = manager.getStreamOnline(stream.name,LOG)。這就是socket.timeout異常發生的地方。

錯誤。它不會在該行上凍結,因爲該行是一個函數調用,它通過其他幾個模塊調用大量其他函數。所以你還不知道程序凍結的地方。此外,該行是不是發生套接字超時的時間點。套接字超時只會發生在像select或recv這樣的低級套接字操作上,在getStreamOnline觸發的活動鏈中會多次調用它。

您需要在調試器中跟蹤代碼或添加打印語句以準確跟蹤發生掛起的位置。它可能是Python中的一個無限循環,但更可能是對OS網絡功能的低級調用。直到你找到錯誤的根源,你什麼也做不了。

P.S.鍵盤中斷是一個合理的線索,說明問題出現在JtvClient.py的第90行左右,所以放入一些打印語句並找出發生了什麼。有可能是一個愚蠢的循環,不斷調用getresponse,或者你可能會調用它的參數錯誤,或者網絡服務器真的是borked。將其縮小到更少的可能性。

+0

我已經更新了我的問題 - 你能再看一次嗎? – Hubro

0

您是否嘗試過使用其他應用程序來打開該連接?鑑於這是生產中的問題,也許你沒有一些防火牆問題。

+0

我更新了我的問題 - 你能再看一次嗎? – Hubro

+0

我想我的答案還是對的。然而,另一種可能性是,連接不會在另一端關閉。 Readline應該阻止,直到數據到來。無論你有網絡問題,還是你的協議本身都在拖延,這樣遠程服務器就不會向你發送你期望的東西。 –

+0

是不是應該由超時解決?超時如何永遠不會發生? – Hubro