Multithreading 如何在适当的时候响应用户,并优雅地处理行为恶劣的第三方服务器?
我有以下情况: 我有一个web服务,它根据单个用户的请求聚合来自某些第三方服务器的数据。对第三方的请求可以是SOAP或带有XML数据的普通urllib2请求,并且每个请求都在单独的线程中完成 以下是我所做工作的总体情况:Multithreading 如何在适当的时候响应用户,并优雅地处理行为恶劣的第三方服务器?,multithreading,web-services,python-2.7,urllib2,soappy,Multithreading,Web Services,Python 2.7,Urllib2,Soappy,我有以下情况: 我有一个web服务,它根据单个用户的请求聚合来自某些第三方服务器的数据。对第三方的请求可以是SOAP或带有XML数据的普通urllib2请求,并且每个请求都在单独的线程中完成 以下是我所做工作的总体情况: ThirdParty1(Thread): def run(self): try: result = SOAPProxy('http://thirdparty.com', timeout=2).method(params)
ThirdParty1(Thread):
def run(self):
try:
result = SOAPProxy('http://thirdparty.com', timeout=2).method(params)
dostuff_and_save(result) # save results on database
except Exception:
log.warn('Ooops')
ThirdParty2(Thread): ...
def myview(params):
thread = [ThirdParty1(), ThirdParty2()]
for t in thread: t.start()
for t in thread: t.join(timeout=2)
return result # this is actually just a token, that I use to retrieve the data saved by the threads
我当前的问题是,当任何第三方服务器挂起时,可靠地返回对用户请求的响应。我尝试在线程连接、SOAPProxy对象上设置超时,并执行socket.setdefaulttimeout
。所有的暂停都不受尊重
我设法找出了SOAPProxy问题,发现它和httplib,文档说:
socket.makefile([mode[,bufsize]])
返回与套接字关联的文件对象。(文件对象在文件>对象中描述。)文件对象引用套接字文件描述符的dup()ped版本,因此>文件对象和套接字对象可以单独关闭或垃圾收集套接字必须处于阻塞模式(不能超时)。可选模式和bufsize参数的解释方式与内置file()函数相同
我找到的所有其他SOAP库,不管是哪种方式,都使用httplib。使事情复杂化的是,我可能需要从请求线程访问数据库,但我不完全理解使用终止线程的后果,我正在考虑在可能的情况下从线程外执行数据库操作
那么我的问题是:
我的web服务如何在不遵守超时的情况下及时响应用户并优雅地处理行为恶劣的第三方服务器
HTTPResponse使用makefile的事实可能没有我想象的那么糟糕,结果证明,
makefile
在默认情况下确实是如此,并且它可能引发超时异常,下面是我尝试的:
在一个控制台上,我打开了netcat-l-p8181'0.0.0',在另一个控制台上,我打开了python2.7并运行:
>>> import socket
>>> af, socktype, proto, canoname, sa = socket.getaddrinfo('0.0.0.0', 8181, 0, socket.SOCK_STREAM)[0]
>>> s=socket.socket(af, socktype, proto)
>>> s.settimeout(.5)
>>> s.connect(sa)
>>> f=s.makefile('rb', 0)
>>> f.readline()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/socket.py", line 430, in readline
data = recv(1)
socket.timeout: timed out
导入套接字
>>>af,socktype,proto,canoname,sa=socket.getaddrinfo('0.0.0.0',8181,0,socket.SOCK\u流)[0]
>>>s=套接字。套接字(af,socktype,proto)
>>>s.settimeout(.5)
>>>s.connect(sa)
>>>f=s.makefile('rb',0)
>>>f.读线()
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“/usr/lib/python2.7/socket.py”,第430行,在readline中
数据=recv(1)
socket.timeout:超时
但是我的问题仍然是如何执行可靠的第三方请求。我想我成功地构建了一个切实可行的解决方案 我要做的第一件事是启动线程,这些线程将请求所需的任何thid party服务器。这非常有效,因为当线程执行阻塞操作(socket.recv())时,GIL不会被保留,这就允许我的服务器在处理请求时执行自己的操作 我删除了线程中的所有副作用,不再与数据库对话,如果请求的响应时间超过预期,我不需要终止它,只需将其保留并忽略即可 当第一个线程启动时,计时器启动,在我的服务器完成任务后,它绝对需要第三方重新运行,它会检查每个线程是否已完成,当它们全部完成或超时时,它会得到每个已完成线程的结果,如下所示:
start, data = time(), []
threads = launch_threads()
# ... do my thing
for t in threads: # wait up to TIMEOUT
timeout = TIMEOUT - (time() - start)
t.join(t)
for t in threads:
if not t.isAlive(): # should not have a race
data.append(t.getdata())
看来,我正在考虑多处理
,如果我需要保留线程,我将减少外部请求的工作量…上面的链接已断开,我还应该注意,python在线程方面并不差,python的线程是用于IO而非处理的。