基于消息属性临时禁用JMS消息的传递

时间:2011-10-09 17:06:03

标签: java jms hornetq

我有一个要求,我目前还不知道是否有可能。如果消息包含指定的属性,我想临时禁用JMS消息的devliery。目前我正在使用HornetQ作为消息提供者。

我们举个例子:

队列包含以下三个条目:

{1, "foo", "A_CATEGORY"}
{2, "bar", "B_CATEGORY"}
{9, "bof", "A_CATEGORY"}

在某个时刻,应用程序必须能够告诉HornetQ消息服务器此时不应传递属于B_CATEGORY的消息(例如,因为B_CATEGORY对象的底层数据库得到更新)。因此,id为2的消息此时将不会被传递,而1和9将被传递,因为它们具有类别对象的不同值。

必须在没有重新启动应用程序的情况下从Java代码中发生。这有可能吗?

感谢您的帮助!


想到这个问题的替代设计方法。假设第一个Queue包含具有所有类别的消息(顺便说一下,不可能为每个类别创建一个队列,因为可能有很多类别)。正常配置该“正常”队列(例如,没有到期,但是DLQ)。

现在,如果侦听器使用此类消息并发现它无法处理属于某个类别的消息,则会将其置于第二个队列中。此队列配置了重新传递延迟以及到期时间。如果现在设置的到期时间足够高(当然不是队列溢出)并且重新传递时间不会太短,那么如果没有上述问题的解决方案,这应该可以解决。

当然,必须计算在无法处理类别期间可以创建多少个队列条目。还有一个类别的可用性可以持续多长时间,以便可以相应地调整重新发送。

2 个答案:

答案 0 :(得分:1)

据我所知,消息驱动bean无法实现。

使用标准JMS使用者可以实现类似的功能:

 MessageConsumer c = session.createConsumer(destination);
 while ( b-category-can-be-processed ) {
     Message m = c.receive();
     // process messages until b category is OK to be processed
 }

 c.close();

 // now create a different consumer with message selector ignoring "B_CATEGORY"
 MessageConsumer c1 = session.createConsumer(destination, "Category <> 'B_CATEGORY'");
 while ( b-is-locked ) {
     Message m = c1.receive();
     // process messages until b category is locked
 }

 c1.close();
 // go to start

此示例假设您可以根据收到的消息告知何时再次处理B.如果没有,那么你可以在一定时间后恢复正常程序。该示例还只显示了一个执行线程。

进一步探索这条路径,你可以看看Spring的DefaultMessageListenerContainer - Spring消息驱动bean。它可以完全按照我的描述进行,但采用更先进的方式。它可以通过消息选择器提供,并且它是实时的,您可以随时更改它。如果将concurrentConsumers设置为高于1,它也会处理多个线程中的消息。

对于将消息重定向到另一个队列而无法处理的解决方案,请注意它会产生额外的流量;你确实希望最后处理你的所有消息,对吧?为什么不把它们留在原处并在适当的时候取出它们呢?你不必估计未来的重新发送延迟,这可能很难。

答案 1 :(得分:0)

您可以使用过滤器创建核心队列(或订阅),并使用管理API停止队列。或者,如果您正在使用嵌入式服务器,则可能会导致服务器队列对象暂停。

由于这是一个非常自定义的功能,您可以使用它嵌入,或在您自己的分支进行特殊调整。