java 使用消息后,如果有任何错误,如何将消息保存在 JMS 消息队列中?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30266631/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to hold messages in JMS Message Queue if there are any error after consuming the message?
提问by Dinesh M
My scenario is - I post message in to queue and once message is consumed I am sending it to third party middleware application. If that middleware application is down then my posted message gone for toss. I do not want to lose that message if middleware application is down instead I want it to be on hold or waiting in the queue. Please suggest, how to handle this scenario?
我的场景是 - 我将消息发布到队列中,一旦消息被消耗,我就会将其发送到第三方中间件应用程序。如果该中间件应用程序关闭,那么我发布的消息就会被扔掉。如果中间件应用程序关闭,我不想丢失该消息,而是希望它被搁置或在队列中等待。请建议,如何处理这种情况?
采纳答案by GionJh
You should create the session like this:
您应该像这样创建会话:
Session session = connection.createSession(false,
Session.CLIENT_ACKNOWLEDGE);
when you try to deliver the message to your third party app:
当您尝试将消息传送到第三方应用时:
If it's working you should acknoledge the message.
If it is down you should'nt acknwoledge it, this way the JMS provider will be able to rediliver it,and the message will not be lost.
message.acknowledge();
如果它正在工作,您应该确认该消息。
如果它宕机了,你不应该承认它,这样 JMS 提供者将能够重新传递它,并且消息不会丢失。
message.acknowledge();
Also, you can take a look at this: JMS AUTO_ACKNOWLEDGE when is it acknowledged?
另外,您可以看看这个:JMS AUTO_ACKNOWLEDGE 何时被确认?
回答by Will Hartung
JMS Queues are not message stores.
JMS 队列不是消息存储。
If you have a "bad message" for which the processing continues to fail, then the JMS server (if configured) will inevitably dump that message to a a "Dead Message Queue", which will slowly fill up until a different process drains it.
如果您有处理继续失败的“坏消息”,那么 JMS 服务器(如果已配置)将不可避免地将该消息转储到“死消息队列”,该队列将缓慢填满,直到不同的进程将其耗尽。
You don't want to keep bad messages in the queue, as they can potentially block the queue (imagine you have 10 consumers, and the top 10 messages are all bad, so all the processes do is continue to flail on bad messages -- stalling the queue).
您不希望将坏消息保留在队列中,因为它们可能会阻塞队列(假设您有 10 个消费者,并且前 10 条消息都是坏消息,因此所有进程所做的就是继续处理坏消息——拖延队列)。
So, you need some mechanism to store the messages in to an exception sink, where they can then later be injected in to the main queue for processing.
因此,您需要某种机制将消息存储到异常接收器中,然后可以将它们注入到主队列中进行处理。
The dead message queue is not this mechanism (don't store messages in a JMS queue), rather it can be a mechanism to ROUTE exceptional messages to a more permanent storage area (i.e. a db table or something else).
死消息队列不是这种机制(不要将消息存储在 JMS 队列中),而是可以将异常消息路由到更永久的存储区域(即 db 表或其他东西)的机制。
Once there, they can be vetted (automatically, manually, whatever) and either redelivered or canceled.
到达那里后,可以对它们进行(自动、手动等),然后重新交付或取消。
But the key point is you need an external mechanism for this, the JMS Server alone isn't the appropriate place for these kind of messages.
但关键是您需要一个外部机制,单独的 JMS 服务器不是这些类型消息的合适位置。
回答by sri
This can be acheived my using session acknowledgement. For this first modify your producer code to use Session.AUTO_ACKNOWLEDGE. While creating Queue session, make AUTO_ACKNOWLEDGE as false. That means consumer has to acknowledge. When the consumer sends acknowledgement of message, then the message will be deleted from the queue, otherwise it will remain in the queue.
这可以通过我使用会话确认来实现。为此,首先修改您的生产者代码以使用 Session.AUTO_ACKNOWLEDGE。创建队列会话时,将 AUTO_ACKNOWLEDGE 设为 false。这意味着消费者必须承认。当消费者发送消息确认时,该消息将从队列中删除,否则将保留在队列中。
Below is the producer code.
下面是生产者代码。
try {
QueueConnectionFactory qcf = AppUtils.getQueueConnectionFactory();
Queue q = AppUtils.getDestination();
QueueConnection qConnection = qcf.createQueueConnection();
QueueSession qSession = qConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
QueueSender qSender = qSession.createSender(q);
qConnection.start();
TextMessage msg = qSession.createTextMessage("Hello");
qSender.send(msg);
qSender.close();
qConnection.close();
} catch (JMSException e) {
// log your error to log file
e.printStackTrace();
}
On the consumer side you have to do the same thing, create a queue session with AUTO_ACKNOWLEDGE as false.
在消费者方面,您必须做同样的事情,创建一个 AUTO_ACKNOWLEDGE 为 false 的队列会话。
After working on your message, you can send acknowledge to delete the message from the queue or the message will remain in the queue.
处理完您的消息后,您可以发送确认以从队列中删除该消息,否则该消息将保留在队列中。
try {
QueueConnectionFactory qcf = getQueueConnectionFactory();
Queue q = getDestination();
QueueConnection qConnection = qcf.createQueueConnection();
QueueSession qSession = qConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
QueueReceiver qReceiver = qSession.createReceiver(q);
qConnection.start();
Message msg = qReceiver.receive();
// here send your message to third party application
//if your third party application is down
if(thirdpartyapp is down){
//here you can raise an exception
//or just do nothing
// you're not sending acknowledgement here so the msg will
//remain in the queue
}else{
msg.acknowledge();//here youre sending ack, so msg will be deleted
qReceiver.close();
qConnection.close();
}
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
回答by Shashi
Although, it's not very clear how your application that consumes messages is designed, I suggest you modify consumer application to consume messages inside a local transaction and post message to third party middle-ware application. If post is successful, then you can commit the transaction which will remove the message from JMS queue. In case your application fails to post message, you can simply rollback transaction which will make the message to reappear in JMS queue. That message will be delivered again.
虽然不是很清楚你的消费消息的应用程序是如何设计的,但我建议你修改消费者应用程序以在本地事务中消费消息并将消息发布到第三方中间件应用程序。如果发布成功,那么您可以提交将从 JMS 队列中删除消息的事务。如果您的应用程序无法发布消息,您可以简单地回滚事务,这将使消息重新出现在 JMS 队列中。该消息将再次传递。