编程语言
首页 > 编程语言> > python-如何在WSGI处理程序中捕获“ [Errno 32]损坏的管道”

python-如何在WSGI处理程序中捕获“ [Errno 32]损坏的管道”

作者:互联网

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时,相应的异常(错误:[Errno 32]管道损坏)被抛出到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)

解决方法:

看起来,当请求终止时会发生的事情是,除了(看似不可捕获)异常回溯之外,从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
    )

但是,这不会使错误消息/回溯消失,但是,除非有人可以提出解决方案,否则这似乎是可以容忍的.

标签:http,gevent,wsgi,python,long-polling
来源: https://codeday.me/bug/20191122/2061309.html