Skip to content

Publisher hangs when doing multiprocessing, but not when threading #1232

Description

@RobertLucian

So I've got the following 3 classes that play the role of PUB(Publisher) and SUB(Subscriber).

formatters = {
    logging.DEBUG: logging.Formatter("[%(name)s] %(message)s"),
    logging.INFO: logging.Formatter("[%(name)s] %(message)s"),
    logging.WARN: logging.Formatter("[%(name)s] %(message)s"),
    logging.ERROR: logging.Formatter("[%(name)s] %(message)s"),
    logging.CRITICAL: logging.Formatter("[%(name)s] %(message)s")
}

class PUBLogger:
    def __init__(self, host, port = 5555, level = logging.DEBUG):
        self._logger = logging.getLogger(__name__)
        self._logger.setLevel(level)
        self.ctx = zmq.Context()
        self.pub = self.ctx.socket(zmq.PUB)
        # self.pub.setsockopt(zmq.LINGER, 0)
        self.pub.connect('tcp://{0}:{1}'.format(socket.gethostbyname(host), port))
        self._handler = PUBHandler(self.pub)
        self._handler.formatters = formatters
        self._logger.addHandler(self._handler)

    @property
    def logger(self):
        return self._logger

class SUBLogger:
    def __init__(self, 
        ip, 
        port = 5555, 
        output_dir = '', 
        logfile_name = 'output.log', 
        stdout = False,
        level = logging.DEBUG):

        self.output_dir = output_dir
        self._logger = logging.getLogger()
        self._logger.setLevel(level)

        self.ctx = zmq.Context()
        self._sub = self.ctx.socket(zmq.SUB)
        self._sub.bind('tcp://*:{1}'.format(ip, port))
        self._sub.setsockopt_string(zmq.SUBSCRIBE, "")

        formatter = logging.Formatter("%(asctime)s;%(levelname)s;%(funcName)s - %(message)s")

        handler = handlers.RotatingFileHandler(os.path.join(output_dir, logfile_name), "w", 100 * 1024 * 1024, 10)
        handler.setLevel(level)
        handler.setFormatter(formatter)
        self._logger.addHandler(handler)

        if stdout is True:
            handler_stdout = logging.StreamHandler(sys.stdout)
            handler_stdout.setLevel(level)
            handler_stdout.setFormatter(formatter)
            self._logger.addHandler(handler_stdout)

    @property
    def sub(self):
        return self._sub

    @property
    def logger(self):
        return self._logger

class ThreadedLoggerSUB(Thread):
    def __init__(self, ip, port = 5555, stdout = False, level = logging.DEBUG):
        super(ThreadedLoggerSUB, self).__init__()
        self._sub_logger = SUBLogger(ip, port, stdout = stdout, level = level)
        self._event = Event()
        self._ready = Event()
    
    def run(self):
        self._ready.set()
        while not self._event.is_set():
            try:
                topic, message = self._sub_logger.sub.recv_multipart(flags = zmq.NOBLOCK)
                if isinstance(topic, str):
                    log_msg = getattr(logging, topic.lower())
                    log_msg(message)
            except zmq.ZMQError as zmq_error:
                if zmq_error.errno == zmq.EAGAIN:
                    pass
        self._sub_logger.sub.close()

    def stop(self):
        self._event.set()

    def wait(self):
        self._ready.wait()

In the main process where everything is coordinated, I start a ThreadedLoggerSUB thread that runs throughout the runtime of the program.
During its runtime, I spin a process within the program with a manager (from multiprocessing module) and in the constructor of the class (let's call the class ThreadToBeRunInSeparateProcess, it's basically inherited from Thread) that's getting instantiated in this separate process, a PUBLogger object is created and the logger object is returned from it.

The problem is that in roughly ~50% of the cases, the logger object in this separate process hangs when I want to log something. When it doesn't hang, I get to see the logs in the main process.

What's interesting is that if I run a ThreadToBeRunInSeparateProcess thread in the main process, it works just fine - I never get to see it hanging up, which tells me, there has got be something going on with the managers.

Do you have any idea why pyzmq is having this problem?

Thank you!

Robert

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions