如何捕获“[Errno 32]断管”在WSGI处理程序中 [英] How to catch "[Errno 32] Broken pipe" in a WSGI handler
问题描述
WSGI对于构建高度并发的HTTP服务器非常有用,可以支持例如但是,长轮询通常会在某些时候由客户端结束长时间运行的HTTP请求;要清理任何资源和打开句柄,应该通知WSGI服务器后端任何此类事件,但是,目前似乎无法在WSGI处理程序中捕获这些事件:
WSGI is extremely useful for building highly concurrent HTTP servers to support e.g. long polling, however, typically, the long running HTTP request will at some point be ended by the client side; to clean up any resources and open handles, the WSGI server backend should be notified of any such events, however, it doesn't currently seem to be possible to catch those events in the WSGI handler:
# 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
时,相应的异常(错误:[Errno] 32]破坏的管道
)在gevent中的某处被抛出,甚至似乎都没有出现在处理程序可能看到它的任何地方:
For example, when using gevent.pywsgi
, the corresponding exception (error: [Errno 32] Broken pipe
) is thrown somewhere inside gevent and never even seems to surface anywhere the handler could potentially see it:
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)
推荐答案
看起来当请求被终止时会发生什么,除了(看似无法捕获的)异常回溯之外,从WSGI处理程序返回的迭代器是 .close()
-d。因此可以确定何时应关闭与响应相关联的任何工人/资源/句柄。这基本上是 werkzeug.wsgi.ClosingIterator 所做的:
Looks like what happens when a request gets terminated is that, in addition to the (seemingly uncatchable) exception traceback, the iterator that was returned from the WSGI handler is .close()
-d. It is thus possible to determine when the any workers/resources/handles associated with the response should be closed. This is basically what werkzeug.wsgi.ClosingIterator does:
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
)
但是这不会使错误消息/回溯无声,但这似乎是可以忍受的除非有人能提出解决方案,甚至可以解决这个问题。
This does not however silence the error message/traceback, but this seems tolerable unless somebody can come up with a solution that can fix even that.
这篇关于如何捕获“[Errno 32]断管”在WSGI处理程序中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!