multithreading - 如何及时响应用户,优雅的处理第三方服务器的不良行为?

标签 multithreading web-services python-2.7 urllib2 soappy

我有以下场景:

我有一个网络服务,可以根据单个用户请求从某些第三方服务器聚合数据。对第三方的请求可以是 SOAP 或带有 XML 数据的普通 urllib2 请求,并且每个请求都在一个单独的线程中完成。

这是我正在做的事情的总体情况:

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 问题并发现它 uses httplib和 httplib deep down uses socket.makefile() ,文档说:

socket.makefile([mode[, bufsize]])

Return a file object associated with the socket. (File objects are described in File > Objects.) The file object references a dup()ped version of the socket file descriptor, so > the file object and socket object may be closed or garbage-collected independently. The socket must be in blocking mode (it can not have a timeout). The optional mode and bufsize arguments are interpreted the same way as by the built-in file() function.

我发现的每个其他 SOAP 库,都以某种方式使用 httplib。使事情复杂化的是,我可能需要从请求线程访问数据库并且我不完全理解用 this sort of strategy 终止线程的后果是什么,我正在考虑在可能的情况下从线程外部执行数据库操作。

那么,我的问题是:

我的 Web 服务如何及时响应用户并在不遵守超时时优雅地处理行为不当的第三方服务器?


HTTPResponse 使用 makefile 的事实可能没有我想象的那么糟糕,事实证明 makefile 确实是 non buffering默认情况下,它可以引发超时异常,这是我尝试过的:

在一个控制台上,我打开了 netcat -l -p 8181 '0.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

但是我的如何进行可靠的第三方请求的问题仍然存在。

最佳答案

我认为我设法构建了一个可靠的解决方案。

我做的第一件事是启动将请求所需的任何第三方服务器的线程。这很好用,因为在线程执行阻塞操作时 GIL 没有保持(就此而言,socket.recv()),这允许我的服务器在处理请求时做它自己的事情。

我从线程中移除了所有副作用,不再与数据库对话,如果一个请求的响应时间超过预期,我不需要终止它,让它保持原状并忽略它。

当第一个线程启动时,计时器启动,在我的服务器完成它之后它绝对需要第三方结果它检查每个线程以查看它们是否完成,当它们全部完成或超时时它得到每个完成线程的结果,看起来像这样:

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())

关于multithreading - 如何及时响应用户,优雅的处理第三方服务器的不良行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15419915/

相关文章:

Java - 同步是否需要 volatile ?

c++ - Qt 线程计算输出到 GUI 中的自己的小部件?

java - CXF JAXRS - 如何 POST 多个参数

python - 当其中一行匹配条件时如何返回数据库实体的总计数

python - 多重处理不适用于计算矩阵叉积的函数

python - getattr/setattr/hasattr/delattr 线程安全吗?

c# - 检查 SendAsync 是否已完成发送

c# - 项目中不存在目标 "MSDeployTestConnection"

web-services - Delphi 2010导入WCF wsdl时锁定然后关闭

python-2.7 - 使用 Anaconda3 在 mac os x 上运行带有 hydrogen 包的原子编辑器