Nipun Talukdar
Nipun Talukdar

Reputation: 5387

How to catch SIGERM, SIGINT from a process running pyzmq?

I am using PYZMQ and it seems I cannot catch SIGTERM anymore. How do I do that for a graceful handling of SIGTERM ?

Below is the code snippet:

from time import sleep
from signal import signal, SIGTERM, SIGINT
from threading import Lock, Thread
try:
    import cPickle as pickle
except ImportError:
    import pickle
import zmq


zmq_poller = None

class server(Thread, object):
    def __init__(self, transport):
        self.context = zmq.Context()
        self.zmq_socket = self.context.socket(zmq.PULL)
        self.zmq_socket.setsockopt(zmq.RCVTIMEO, 2000)
        self.zmq_socket.bind(transport)
        self.keep_running = True
        Thread.__init__(self)

    def process_data(self, data):
        data = self.decode(data)

    def decode(self, data):
        return pickle.loads(data)

    def run(self):
        while self.keep_running:
            try:
                data = self.zmq_socket.recv()
                self.process_data(data)
            except zmq.error.Again:
                pass
            except zmq.error as e:
                print e

    def stop(self):
        self.keep_running = False

def handle_stop(signum=None, frame=None):
    if zmq_poller:
        zmq_poller.stop()

if __name__ == '__main__':
    signal(SIGTERM, handle_stop)
    signal(SIGINT, handle_stop)
    mc = server('ipc:///tmp/abc')
    zmq_poller = mc
    mc.setDaemon(True)
    mc.start()
    mc.join()
    sleep(100)

As we see, the handle_stop signal handler is not invoked if I send SIGTERM, SIGINT to the process

Upvotes: 1

Views: 882

Answers (1)

blockchaindev
blockchaindev

Reputation: 3196

The reason for your problem is that your main thread is blocked on threading.Thread.join Execution of Python signal handlers:

A Python signal handler does not get executed inside the low-level (C) signal handler. Instead, the low-level signal handler sets a flag which tells the virtual machine to execute the corresponding Python signal handler at a later point(for example at the next bytecode instruction)

A long-running calculation implemented purely in C (such as regular expression matching on a large body of text) may run uninterrupted for an arbitrary amount of time, regardless of any signals received. The Python signal handlers will be called when the calculation finishes.

Pre-3.3, the signal module definitely doesn't expose the tools you'd need to fix this problem yourself. So, if you can't upgrade to 3.3, the solution is to wait on something interruptible, like a Condition or an Event. The child thread notifies the event right before it quits, and the main thread waits on the event before it joins the child thread.

Upvotes: 1

Related Questions