josh josh - 2 months ago 25
Python Question

Handling keyboard interrupt in async zmq

I'm making a ZeroMQ server in

pyzmq
using
asyncio
. I'm trying to gracefully handle stopping the server, but there's very little documentation on the async module and there doesn't seem to be a simple way to handle stopping the current poll/await. Stopping the loop in the
.stop
method doesn't do much and won't actually exit.

import zmq
import zmq.asyncio
import asyncio

class ZMQHandler():
def __init__(self):
self.loop = zmq.asyncio.ZMQEventLoop()
asyncio.set_event_loop(self.loop)
self.context = zmq.asyncio.Context()
self.socket = self.context.socket(zmq.DEALER)
self.socket.bind('tcp://127.0.0.1:5000')
self.socket.linger = -1


def start(self):
asyncio.ensure_future(self.listen())
self.loop.run_forever()

def stop(self):
print('Stopping')
self.loop.stop()

async def listen(self):
self.raw = await self.socket.recv()
asyncio.ensure_future(self.listen())


Here's some example code that would start this:

daemon = ZMQHandler()

def signal_handler(num, frame):
daemon.stop()

signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGINT, signal_handler)

daemon.start()


How do I gracefully stop this when it's running? When I call
self.socket.close()
, I get the error
zmq.error.ZMQError: Socket operation on non-socket
, and if I call
self.context.destroy()
it basically complains that the sockets weren't terminated cleanly with
ETERM
.

Answer

It ended up being a bug in the implementation of pyzmq. The bug was fixed and now calling loop.stop() works as intended.