【问题标题】:jms message non persistent redelivery after stop-start appServer停止启动 appServer 后 jms 消息非持久性重新传递
【发布时间】:2017-06-27 15:21:18
【问题描述】:

使用 jms 队列。

ejb 发件人:

@Resource(lookup = "jms/csPdvQueue")
private Queue csPdvQueue;
@Inject
private JMSContext jmsContext;

方法发送消息:

public void asynchWatched(Pdv pdv, boolean pending) {
   jmsContext.createProducer().setDeliveryMode(DeliveryMode.NON_PERSISTENT);
   jmsContext.createProducer().send(csPdvQueue, pdv);
}

ejb 消费者:

@MessageDriven(mappedName = "jms/csPdvQueue")
public class PdvProcessorMdb implements MessageListener {

    @Override
    public void onMessage(Message message) {
    ... execute some businesslogic...
    }

}

如果应用服务器(payara)在消息消费(onMessage)期间退出,事务正确回滚。

当应用服务器再次启动时,即使我设置了 DeliveryMode.NON_PERSISTENT,消息也会重新传递。

我想避免消息重新传递。

有可能(以及如何)?

【问题讨论】:

  • "当启动 appServer 时,从消费者那里接收到相同的消息,但发送者没有发送任何东西。" - 你能解释得更好吗?您如何从消费者那里接收信息 - 消费者不发送消息而是接收消息。重启后是否收到相同的消息?

标签: jakarta-ee glassfish payara


【解决方案1】:

发送消息时,你做setDeliveryMode(DeliveryMode.NON_PERSISTENT);,这意味着消息在消息代理重启之间不会被保存。如果您在嵌入式模式下使用 OpenMQ 代理(默认),它将与服务器一起重新启动。所以重启后消息不存在,无法再次发送。

更新:

但是,您的代码在与发送消息的生产者不同的生产者上设置传递模式(创建生产者,设置传递模式,然后丢弃;下一行创建一个新的生产者,发送消息)。 您需要将创建的生产者存储在一个变量中,设置交付方式,然后使用同一个生产者发送消息:

public void asynchWatched(Pdv pdv, boolean pending) {
   JMSProducer producer = jmsContext.createProducer();
   producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
   producer.send(csPdvQueue, pdv);
}

您可以利用流畅的 API 将其缩短:

public void asynchWatched(Pdv pdv, boolean pending) {
   jmsContext.createProducer()
     .setDeliveryMode(DeliveryMode.NON_PERSISTENT);
     .send(csPdvQueue, pdv);
}

【讨论】:

  • 使用嵌入式消息代理。将代码发布在帖子上,asynchWatched 发送消息 -> onMessage 接收消息 -> 在处理消息期间,停止服务器 -> 重新启动服务器 -> onMessage 接收消息。
  • 感谢您的解释。我现在意识到您确实希望不再发送消息。因此,您正确地希望设置传递模式 NON_PERSISTENT。但是代码将其设置在不同的生产者身上。您必须存储创建的生产者,在其上设置传递模式,然后使用同一生产者发送消息。请参阅我的更新答案。
  • 显然可以。我为我的愚蠢错误道歉!
猜你喜欢
  • 2020-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-22
  • 2020-03-29
  • 2011-03-27
相关资源
最近更新 更多