Python ActiveMQ:单个生产者、多个消费者
我有一个使用ActiveMQ的消息队列。web请求以persistency=True将消息放入队列。现在,我有两个消费者都作为单独的会话连接到此队列。消费者1始终确认消息,但消费者2从未确认 现在,我读到这样一篇文章: JMS队列实现负载平衡器语义。只需一条信息就可以了 仅由一个消费者接收。如果没有消费者 邮件发送时可用,它将保留到 消费者可以处理消息。如果消费者 接收消息,但在关闭前未确认该消息,然后 消息将重新传递给另一个消费者。一个队列可以有多个队列 消息的使用者在可用使用者之间负载平衡 我从中了解到的是,我希望消费者1最终能够处理所有消息,因为它总是承认。由于使用者2未确认,因此应将消息发送给使用者1 但我注意到的是: 1.当我提交请求时,我只看到消费者1收到第二次请求。另一个请求没有显示,它存储在ActiveMQ中。我想应该是消费者2没有确认。那么,下一步应该是消费者1吗 我只需要确保消息只由一个消费者处理。在我的例子中,这个消费者是国家(站点)X中的一台机器。每个消息只需要在一个国家(机器)中处理。但是所有国家(机器)都应该收到这个信息。如果消息中的国家id匹配,它将确认。因此,将只发送1条确认/消息 我接收/处理消息的代码如下所示:Python ActiveMQ:单个生产者、多个消费者,python,jms,activemq,Python,Jms,Activemq,我有一个使用ActiveMQ的消息队列。web请求以persistency=True将消息放入队列。现在,我有两个消费者都作为单独的会话连接到此队列。消费者1始终确认消息,但消费者2从未确认 现在,我读到这样一篇文章: JMS队列实现负载平衡器语义。只需一条信息就可以了 仅由一个消费者接收。如果没有消费者 邮件发送时可用,它将保留到 消费者可以处理消息。如果消费者 接收消息,但在关闭前未确认该消息,然后 消息将重新传递给另一个消费者。一个队列可以有多个队列 消息的使用者在可用使用者之间负载平衡
# --------------------------------------------- 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应用程序中实现这个独立的进程,该进程持续监视队列并使用消息