我有一个简单的python脚本,用于更新数据库中justin.tv流的状态。这是一个基于Django的Web应用程序。在我将它移动到我的生产服务器之前,这个脚本运行得很好,但现在它有超时或冻结的问题。我通过添加try / except块并使脚本重试来解决超时问题,但我仍然无法弄清楚冻结问题。
我知道它冻结了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 @ bar:/.../ honstreams / honstreams#python website / scripts / updateStreamStatus.py
检查angrytestie ...因为状态没有改变而跳过angrytestie 检查chustream ...因为状态没有改变而跳过chustream 检查cilantrogamer ...因为状态没有改变而跳过cilantrogamer | < - Caret坐在这里无限地闪烁着
每次冻结并发送键盘中断时,它都在 socket.py 的同一行:
root@husta:/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 :(得分:0)
在JtvClient.py中,它使用httplib来处理连接。您是否尝试过将其更改为使用httplib2?
除了在黑暗中刺伤之外,我还会在此代码中添加大量日志记录语句,以便跟踪实际发生的情况以及卡住的位置。然后我会确保它被卡住的点可以在套接字上超时(这通常涉及monkeypatching或分叉代码库),这样东西就会失败而不是挂起。
你说:
我知道它在行streamOnline = manager.getStreamOnline(stream.name,LOG)上冻结了。这与发生socket.timeout异常的点相同。
错误。它不会冻结在该行上,因为该行是一个函数调用,它通过几个级别的其他模块调用许多其他函数。所以你还不知道程序冻结的地方。此外,该行是 NOT 发生套接字超时的点。套接字超时仅发生在低级别套接字操作(如select或recv)上,该操作在getStreamOnline触发的活动链中被多次调用。
您需要在调试器中跟踪代码或添加print语句以准确跟踪挂起的位置。它可能是Python中的无限循环,但更可能是对OS网络功能的低级调用。在找到错误来源之前,您无法做任何事情。
P.S。键盘中断是一个合理的线索,问题是在JtvClient.py中的第90行,所以放入一些打印语句并找出会发生什么。可能有一个愚蠢的循环,一直在调用getresponse,或者你可能用错误的参数调用它,或者网络服务器可能真的被borked。将其缩小到更少的可能性。
答案 1 :(得分:0)
您是否尝试过使用其他应用程序打开该连接?鉴于它是生产中的一个问题,也许你没有一些防火墙问题。
答案 2 :(得分: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)
哪个解决了它