WSGI对于构建高度并发的HTTP服务器非常有用,可以支持例如但是,长轮询,通常,长时间运行的HTTP请求将在某个时候由客户端结束;要清理任何资源和打开句柄,应该通知WSGI服务器后端任何此类事件,但是,目前似乎无法在WSGI处理程序中捕获这些事件:
# pseudocode example
def application(env, start_response):
start_response(...)
q = Queue()
ev_handle = register_event_handler(lambda event, arg: q.put((event, arg)))
# ??? need to call e.g. ev_handle.unregister() when the HTTP request is terminated
return iter(lambda: render(q.get()), None)
例如,当使用gevent.pywsgi
时,相应的异常(error: [Errno 32] Broken pipe
)会被抛出到gevent中的某个地方,甚至似乎都没有出现在处理程序可能看到它的任何地方:
Traceback (most recent call last):
File "/Users/erik.allik/.virtualenvs/myproj/lib/python2.7/site-packages/gevent/pywsgi.py", line 508, in handle_one_response
self.run_application()
File "/Users/erik.allik/.virtualenvs/myproj/lib/python2.7/site-packages/gevent/pywsgi.py", line 495, in run_application
self.process_result()
File "/Users/erik.allik/.virtualenvs/myproj/lib/python2.7/site-packages/gevent/pywsgi.py", line 486, in process_result
self.write(data)
File "/Users/erik.allik/.virtualenvs/myproj/lib/python2.7/site-packages/gevent/pywsgi.py", line 376, in write
self._write(data)
File "/Users/erik.allik/.virtualenvs/myproj/lib/python2.7/site-packages/gevent/pywsgi.py", line 369, in _write
self._sendall(data)
File "/Users/erik.allik/.virtualenvs/myproj/lib/python2.7/site-packages/gevent/pywsgi.py", line 355, in _sendall
self.socket.sendall(data)
File "/Users/erik.allik/.virtualenvs/myproj/lib/python2.7/site-packages/gevent/socket.py", line 458, in sendall
data_sent += self.send(_get_memory(data, data_sent), flags)
File "/Users/erik.allik/.virtualenvs/myproj/lib/python2.7/site-packages/gevent/socket.py", line 435, in send
return sock.send(data, flags)
答案 0 :(得分:3)
看起来当请求被终止时会发生的事情是,除了(看似无法捕获的)异常回溯之外,从WSGI处理程序返回的迭代器是.close()
- d。因此,可以确定何时应关闭与响应相关联的任何工人/资源/句柄。这基本上是werkzeug.wsgi.ClosingIterator所做的:
class ClosingIterator(object):
def __init__(self, iterable, on_close):
iterator = iter(iterable)
self.close = on_close
def __iter__(self):
return self
def __next__(self):
return self._next()
def application(env, start_response):
start_response(...)
q = Queue()
ev_handle = register_event_handler(lambda event, arg: q.put((event, arg)))
return ClosingIterator(
iter(lambda: render(q.get()), None),
on_close=ev_handle.unregister
)
然而,这并没有使错误消息/追溯变得沉默,但这似乎是可以忍受的,除非有人能提出一个解决方案,甚至可以解决这个问题。