我正在尝试编写一个使用JMS发布订阅模型的应用程序。但是我遇到了挫折,我希望能够让发布者从主题中删除消息。用例是我拥有持久的订阅者,活跃的订阅者将获得消息(因为它或多或少是即时的),但如果有非活动订阅者并且发布者决定消息是错误的,我想让他能够删除消息这样订户一旦活跃就不会再收到了。 问题是,我不知道如何做到这一点。 对于提供商,我决定使用glassfish的实现,但如果其他替代方案提供此功能,我可以切换。
谢谢。
答案 0 :(得分:7)
JMS是一种异步消息传递形式,因此发布者和订阅者在设计上是分离的。这意味着没有机制可以满足您的要求。对于在发布时处于活动状态的订阅者,他们将使用该消息而不能及时接收删除消息以对其进行操作。如果订阅者处于离线状态,那么他们会,但异步消息应该是原子的。如果您继续设计其他响应者的答案(创建删除消息并要求重新连接消费者以读取整个队列以查找删除消息),那么您将创建一种情况,其中系统的行为根据是否有所不同在发布特定消息/删除组合时,订阅者是否在线。还存在竞争条件,其中订户在发布者发出删除消息之前完成对保留消息的读取。这意味着您必须将重要的逻辑放入订阅者以协调这些条件,甚至更多地协调竞争条件。
这种做法的公认方法就是所谓的补偿交易。"在生产者和消费者不共享单个工作单元或共享公共状态(例如使用相同的DB来存储状态)的任何系统中,退出或纠正先前的事务需要第二个事务来反转第一个事务。消费者当然必须能够正确地应用补偿交易。使用此模式时,结果是所有订阅者都表现出相同的行为,无论消息是在消费者重新启动后是实时消耗还是批量消费。
请注意,补偿交易与"删除消息不同。"其他受访者答案中提出的删除消息是一种影响消息流本身的命令和控制形式。另一方面,补偿事务通过系统状态的事务更新来影响系统的状态。
作为一般规则,您从不希望通过使用命令和控制功能操纵消息流来管理系统状态。这很脆弱,容易受到攻击,很难进行审计或调试。相反,设计系统以根据服务质量约束传递每条消息并处理所有消息。完全在应用程序中处理状态更改(包括撤消先前操作)。
例如,在银行业务中,交易会引发诸如透支费等次要影响,一个常见的程序是“备忘录后”。白天的交易,然后在银行关闭后分批批量应用。这样可以在之前调整错误,从而导致透支费用。最近,这些交易是实时应用的,但触发器被扣留,直到当天的账簿关闭,这样才能达到相同的结果。
答案 1 :(得分:1)
JMS API不允许从任何目标(队列或主题)中删除邮件。虽然我相信特定的JMX提供商提供他们自己的专有工具来管理他们的状态,例如使用JMX。尝试检查一下您的JMS提供程序,但要小心:即使您找到解决方案,它也无法在不同的JMS提供程序之间移植。
“删除”消息的一种合法方式是使用其生存时间:
publish(Topic topic, Message message, int deliveryMode, int priority, long timeToLive)
。可能对你来说已经足够了。
如果它不适用于您的应用程序,请解决应用程序级别的问题。例如,为每条消息附加唯一ID,并发布具有更高优先级的特殊“删除”消息,这将是一种删除具有相同ID的“真实”消息的命令。
答案 2 :(得分:-1)
您已让生产者发送delete
消息,消费者需要在开始处理之前阅读所有消息。