如何捕获“[Errno 32]断管”在WSGI处理程序中 [英] How to catch "[Errno 32] Broken pipe" in a WSGI handler

查看:152
本文介绍了如何捕获“[Errno 32]断管”在WSGI处理程序中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆