Responding to client disconnects using bottle and gevent.wsgi?

岁酱吖の 提交于 2019-12-13 03:27:43

问题


I have a small asynchronous server implemented using bottle and gevent.wsgi. There is a routine used to implement long poll that looks pretty much like the "Event Callbacks" example in the bottle documentation:

def worker(body):
  msg = msgbus.recv()
  body.put(msg)
  body.put(StopIteration)

@route('/poll')
def poll():
  body = gevent.queue.Queue()
  worker = gevent.spawn(worker, body)
  return body

Here, msgbus is a ZMQ sub socket.

This all works fine, but if a client breaks the connection while worker is blocked on msgbus.recv(), that greenlet task will hang around "forever" (well, until a message is received), and will only find out about the disconnected client when it attempts to send a response.

I can use msgbus.poll(timeout=something) if I don't want to block forever waiting for ipc messages, but I still can't detect a client disconnect.

What I want to do is get something like a reference to the client socket so that I can use it in some kind of select or poll loop, or get some sort of asynchronous notification inside my greenlet, but I'm not sure how to accomplish either of these things with these frameworks (bottle and gevent).

Is there a way to get notified of client disconnects?


回答1:


Aha! The wsgi.input variable, at least under gevent.wsgi, has an rfile member that is a file-like object. This doesn't appear to be required by the WSGI spec, so it might not work with other servers.

With this I was able to modify my code to look something like:

def worker(body, rfile):
  poll = zmq.Poller()
  poll.register(msgbus)
  poll.register(rfile, zmq.POLLIN)

  while True:
    events = dict(poll.poll())

    if rfile.fileno() in events:
      # client disconnect!
      break

    if msgbus in events:
      msg = msgbus.recv()
      body.put(msg)
      break

    body.put(StopIteration)

@route('/poll')
def poll():
  rfile = bottle.request.environ['wsgi.input'].rfile
  body = gevent.queue.Queue()
  worker = gevent.spawn(worker, body, rfile)
  return body

And this works great...

...except on OpenShift, where you will have to use the alternate frontend on port 8000 with websockets support.



来源:https://stackoverflow.com/questions/20110830/responding-to-client-disconnects-using-bottle-and-gevent-wsgi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!