Python多处理日志记录失败,qsize()无限期增长

时间:2018-12-12 20:33:59

标签: python python-3.x logging python-multiprocessing django-rq

对于背景: 我在将日志发送到AWS Cloudwatch时将django与django_rq工作者一起使用(为简洁起见,可能省略了详细信息...)。随机地,从工作人员发出的日志停止将其发送到CloudWatchLogger处理程序。这个CloudWatchLogger被包装在multiprocessing_logging包装器中,我们称之为MPLogger。

在MPLogger的emit()函数中,如果我调用print(self.queue.qsize()),我会看到当故障开始时,qsize永远永久地变大,而self.queue.empty()在_receive()函数中返回True,从而导致CloudWatchLogger的emit()方法再也不会被调用...

您知道什么可能导致此锁定吗? ...或者我该如何调试引起它的原因?谢谢!我将不胜感激任何反馈。下面的代码:

在MPLogger中:

# _receive() is running in a thread, self.sub_handler is CloudWatchLogger
def _receive(self):
    while not (self._is_closed and self.queue.empty()):
        try:
            record = self.queue.get(timeout=0.2)
            self.sub_handler.emit(record)
        except (KeyboardInterrupt, SystemExit):
            raise
        except EOFError:
            break
        except queue.Empty:
            pass  # This periodically checks if the logger is closed.
        except:
            traceback.print_exc(file=sys.stderr)

    self.queue.close()
    self.queue.join_thread()

def emit(self, record):
    try:
        s = self._format_record(record)
        self.queue.put_nowait(record)
    except (KeyboardInterrupt, SystemExit):
        raise
    except:
        self.handleError(record)

在CloudWatchLogger中:

def emit(self, message):
    cwl_message = dict(timestamp=int(message.created * 1000), message=self.format(message))

    if self.stream_name not in self.queues:
        # start _batch_sender() in a thread referencing this queue
        self.make_queue_and_thread(stream_name)
    self.queues[stream_name].put(cwl_message)

# batch_sender() in a thread
def batch_sender(self, my_queue, stream_name, send_interval, max_batch_size, max_batch_count):
    msg = None

    # See https://boto3.readthedocs.io/en/latest/reference/services/logs.html#CloudWatchLogs.Client.put_log_events
    while msg != self.END:
        cur_batch = [] if msg is None or msg == self.FLUSH else [msg]
        cur_batch_size = sum(size(msg) for msg in cur_batch)
        cur_batch_msg_count = len(cur_batch)
        cur_batch_deadline = time.time() + send_interval
        while True:
            try:
                msg = my_queue.get(block=True, timeout=max(0, cur_batch_deadline-time.time()))
                if size(msg) > max_batch_size:
                    msg = truncate(msg)
            except queue.Empty:
                # If the queue is empty, we don't want to reprocess the previous message
                msg = None
            if msg is None \
               or msg == self.END \
               or msg == self.FLUSH \
               or cur_batch_size + size(msg) > max_batch_size \
               or cur_batch_msg_count >= max_batch_count \
               or time.time() >= cur_batch_deadline:
                self._submit_batch(cur_batch, stream_name)
                if msg is not None:
                    # We don't want to call task_done if the queue was empty and we didn't receive anything new
                    my_queue.task_done()
                break
            elif msg:
                cur_batch_size += size(msg)
                cur_batch_msg_count += 1
                cur_batch.append(msg)
                my_queue.task_done()

0 个答案:

没有答案