Python ActiveMQ:单个生产者、多个消费者

Python ActiveMQ:单个生产者、多个消费者,python,jms,activemq,Python,Jms,Activemq,我有一个使用ActiveMQ的消息队列。web请求以persistency=True将消息放入队列。现在,我有两个消费者都作为单独的会话连接到此队列。消费者1始终确认消息,但消费者2从未确认 现在,我读到这样一篇文章: JMS队列实现负载平衡器语义。只需一条信息就可以了 仅由一个消费者接收。如果没有消费者 邮件发送时可用,它将保留到 消费者可以处理消息。如果消费者 接收消息,但在关闭前未确认该消息,然后 消息将重新传递给另一个消费者。一个队列可以有多个队列 消息的使用者在可用使用者之间负载平衡

我有一个使用ActiveMQ的消息队列。web请求以persistency=True将消息放入队列。现在,我有两个消费者都作为单独的会话连接到此队列。消费者1始终确认消息,但消费者2从未确认

现在,我读到这样一篇文章:

JMS队列实现负载平衡器语义。只需一条信息就可以了 仅由一个消费者接收。如果没有消费者 邮件发送时可用,它将保留到 消费者可以处理消息。如果消费者 接收消息,但在关闭前未确认该消息,然后 消息将重新传递给另一个消费者。一个队列可以有多个队列 消息的使用者在可用使用者之间负载平衡

我从中了解到的是,我希望消费者1最终能够处理所有消息,因为它总是承认。由于使用者2未确认,因此应将消息发送给使用者1

但我注意到的是: 1.当我提交请求时,我只看到消费者1收到第二次请求。另一个请求没有显示,它存储在ActiveMQ中。我想应该是消费者2没有确认。那么,下一步应该是消费者1吗

我只需要确保消息只由一个消费者处理。在我的例子中,这个消费者是国家(站点)X中的一台机器。每个消息只需要在一个国家(机器)中处理。但是所有国家(机器)都应该收到这个信息。如果消息中的国家id匹配,它将确认。因此,将只发送1条确认/消息

我接收/处理消息的代码如下所示:

# --------------------------------------------- MODULE IMPORT ---------------------------------------------------------#
import argparse
import json
import logging
import multiprocessing as mp
import sys

import stomp
from tvpv_portal.services.msgbkr import MsgBkr
from utils import util


# --------------------------------------------- DEVELOPMENT CODE ------------------------------------------------------#
log = logging.getLogger(__name__)


class MessageProcessingListener(stomp.ConnectionListener):
    """This class is responsible for processing (consuming) the messages from ActiveMQ."""

    def __init__(self, conn, cb):
        """Initialization.

        Args:
            conn -- Connection object
            cb   -- Callback function
        """

        self._conn = conn
        self._cb = cb

    def on_error(self, headers, body):
        """When we get an error.

        Args:
            headers -- Message header
            body    -- Message body
        """

        log.error('Received error=%s', body)

    def on_message(self, headers, body):
        """When we receive a message.

        Args:
            headers -- Message header
            body    -- Message body
        """

        log.info('Received message')

        # Deserialize the message.
        item = json.loads(body)

        import pprint
        pprint.pprint(item)

        # TODO: check if msg is to be handled by this SITE. If so, acknowledge and queue it. Otherwise, ignore.

        # Put message into queue via callback (queue.put) function.
        #self._cb(item)

        # TODO: we only send acknowledge if we are supposed to process this message.
        # Send acknowledgement to ActiveMQ indicating message is consumed.
        self._conn.ack(headers['message-id'], headers['subscription'])


def worker(q):
    """Worker to retrieve item from queue and process it.

    Args:
        q -- Queue
    """

    # Run in an infinite loop. Get an item from the queue to process it. We MUST call q.task_done() to indicate
    # that item is processed to prevent deadlock.
    while True:
        try:
            item = q.get()

            # TODO: We will call external script from here to run on Netbatch in the future.
            log.info('Processed message')

        finally:
            q.task_done()


def flash_mq_rst_handler_main():
    """Main entry to the request handler."""

    # Define arguments.
    parser = argparse.ArgumentParser(description='Flash message queue request handler script',
                                     formatter_class=argparse.ArgumentDefaultsHelpFormatter,
                                     add_help=False)

    opts = parser.add_argument_group('Options')
    opts.add_argument('-h', '--help', action='help',
                      help='Show this help message and exit')
    opts.add_argument('--workers', metavar='val', type=int, default=4,
                      help='Number of worker processes')
    opts.add_argument('--log', metavar='file', type=util.get_resolved_abspath, default='flash_mq_rst_handler.log',
                      help='Log file')

    # Parse arguments.
    args = parser.parse_args()

    # Setup logger.
    util.configure_logger(args.log)
    log.info('Command line %s', ' '.join(map(str, sys.argv)))

    # Create a managed queue to store messages retrieved from message queue.
    queue = mp.Manager().JoinableQueue()

    # Instantiate consumer message broker + ensure connection.
    consumer = MsgBkr(producer=False)
    if not consumer.is_connected():
        log.critical('Unable to connect to message queue; please debug')
        sys.exit(1)

    # Register listener with consumer + queue.put as the callback function to trigger when a message is received.
    consumer.set_listener('message_processing_listener', MessageProcessingListener, cb=queue.put)

    # Run in an infinite loop to wait form messages.
    try:
        log.info('Create pool with worker=%d to process messages', args.workers)
        with mp.Pool(processes=args.workers) as pool:
            p = pool.apply_async(worker, (queue,))
            p.get()
    except KeyboardInterrupt:
        pass

    # See MsgBkr. It will close the connection during exit() so we don't have to do it.
    sys.exit(0)


if __name__ == '__main__':
    flash_mq_rst_handler_main()

通过JMS桥解决了这一问题:


能够让它配置创建N+1队列。源(传入)队列是放置所有消息的位置。根据消息中的某个选择器(如标题中的“some_key”:“some_value”),可以将消息路由到N个目标(传出)队列之一。然后,每个站点都可以侦听特定队列中的消息。同一目标队列上的多个使用者将以循环方式获取消息

。看起来我需要研究ActiveMQ中的扇出交换的等价物。好的,我需要的是一个队列->N队列桥来执行路由:请参阅如何在Flask应用程序中实现这个独立的进程,该进程持续监视队列并使用消息