title: How to resolve Tornado + ZMQ error
body: <p>Like everyone else, I'm working through a chat PoC using Tornado (SockJS-Tornado) + pyzmq.</p>
  
  <p>The overall idea is to have N tornado instances, each with connected websocket clients, exchanging messages through a ZMQ Device. In other words a websocket client on instance A publishes to a ZMQ Forwarder. Instances B &amp; C have Handlers that are subscribed to the Forwarder so that matching topics are relayed to the websocket clients of B &amp; C. And yes, the clients on B &amp; C also have publisher sockets that publish to the Forwarder.</p>
  
  <p>This all works fine but my problem is that if one of the connected clients disconnects unexpectedly (e.g. closes or refreshes the browser tab), then I get a deluge of errors like this: </p>
  
  <pre><code>ERROR:tornado.application:Exception in callback None
  Traceback (most recent call last):
    File ".../tornado/ioloop.py", line 836, in start
    fd_obj, handler_func = self._handlers[fd]
  KeyError: 246850817
  ERROR:tornado.application:Exception in callback None
  Traceback (most recent call last):
    File ".../tornado/ioloop.py", line 836, in start
    fd_obj, handler_func = self._handlers[fd]
  KeyError: 246850817
  </code></pre>
  
  <p>So, at the application level, there's a single Context, but each Handler instantiated gets its own Publisher and Subscriber sockets. The Subscriber sockets use ZMQStream, like this:</p>
  
  <pre><code>   def _set_up_sockets(self):
      self.publisher = self.context.socket(zmq.PUB)
      self.publisher.connect('tcp://127.0.0.1:5559')
      self.subscriber = self.context.socket(zmq.SUB)
      self.subscriber.connect('tcp://127.0.0.1:5560')
      self.subscriber.setsockopt(zmq.SUBSCRIBE, "_NOROOM_")
      stream = zmqstream.ZMQStream(self.subscriber,
                                   io_loop=self.session.server.io_loop)
      stream.on_recv(self.echo)
  </code></pre>
  
  <p>The ioloop passed to ZMQStream is the global io_loop created at application startup:</p>
  
  <pre><code>ioloop.install()
  io_loop = IOLoop.instance()
  </code></pre>
  
  <p>It's actually an instance of the ZMQ subclass of the Tornado IOLoop. Any idea what's causing this error? I have some cleanup methods, <code>on_connection_close</code> and <code>on_close</code> but they don't seem to get called at any point. </p>
  
  <p>Oh, this is Python 2.7.8, ZeroMQ 4.0.4, PyZMQ 14.4.0 (same thing happened with 14.3.1).</p>
  
  <p>Thanks in advance</p>