How do I hold a jms message in queue until it is saved? - jms

I just started using Weblogic JMS. I was able to send messages to the queue and pull them off with a messagebean. Now I want to save the message to a database.
So my question is, how do I tell JMS not to delete the message from the queue until I have successfully written the message to the database?
Thanks

I was able to send messages to the queue and pull them off with a
messagebean.
I suppose you are talking about message-driven bean (MDB)?
So my question is, how do I tell JMS not to delete the message from
the queue until I have successfully written the message to the
database?
MDBs are part of implicit container-managed transaction and the message will not be removed as long as your transaction hasn't commited (that is, as long as your onMessage method hasn't reached its end).
In case of rollback (i.e. you throw an exception or call context.setRollbackOnly() on the MessageDrivenContext), message will be redelivered. You can avoid this behaviour by making transaction bean-managed or using #TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED), but in your situation that should not be the case. Stick with default configuration and everything should work as you wish.

Related

spring integration with jms, weblogic, message appears in queue even after message is consumed into channel

I am using spring integration with weblogic jms. my logic is to put the json object in jms queue, and consume it from queue into the channel, validate it and route it based on a particular field. if there is any error, do the fix and put it back into the queue. I have two issues. 1. when the message is consumed into the object, I still can see the object as pending in administrative console of weblogic. 2. After fixing the validation, if put the modified object in the queue, I am getting the original object from queue.
<int-jms:outbound-channel-adapter id="jmsOutbound"
channel="requestChannel" connection-factory="queueConnectionFactory"
destination="inputQueue" />
<int-jms:message-driven-channel-adapter
id="jmsInbound" connection-factory="queueConnectionFactory"
destination="inputQueue" channel="routingChannel" />
if (message.getHeaders().get("documentType").equals("sec"))
routingChannels.add(outboundSecChannel);
else if (message.getHeaders().get("documentType").equals("unds"))
routingChannels.add(outboundFChannel);
else if (message.getHeaders().get("documentType").equals("CH"))
routingChannels.add(outboundAChannel);
else{
routingChannels.add(errorChannel);
}
putting in channel using routing
thanks for your help.
I think you should distinguish the consuming part from producing to the separate threads. I don't tell that you have to switch to the transactions, but at least the simple acknowledge for the consumed message should be done.
Since you tell that you are going to putt the message back to the queue, that's definitely the fact to always acknowledge the consumed message independently of the error fact. So, what I suggest is something like to place a QueueChannel or an ExecutorChannel somewhere after <int-jms:message-driven-channel-adapter> and before <int-jms:outbound-channel-adapter> to let them do their hard work with the WebLogic JMS in their own threads.

Getting 'MQCC_FAILED' reason '2072' 'MQRC_SYNCPOINT_NOT_AVAILABLE' while attempting to send a message

I have an MDB (mdbA) in JBoss 5.1 GA which listens to an MQ 7.0 queue. After reception, the message is persisted to a MySQL database and I would like to send the message to another queue (queueB) and then continue processing the message in mdbA which does some more inserts and sends a message to a HornetQ. All works fine for the first message and I see the message in Database as well as queueB and hornetQ. For all subsequent messages, the "send to queueB" results in 'MQRC_SYNCPOINT_NOT_AVAILABLE'error 2072.
My mdbA has the following annotations.
#TransactionAttribute (TransactionAttributeType.REQUIRED)
#Service
Please let me know if I need to provide more information.
Could someone please assist?
Solved a similar issue in WebLogic where the MDB itself was annotated #TransactionManagement(TransactionManagementType.BEAN) and choosing instead #TransactionManagement(TransactionManagementType.CONTAINER) solved the issue, with no Transaction attribute on methods, hence default REQUIRED.
In fact, sound MDB's would likely delegate transactions to the container and not attempt to control them explicitly in code. If you use BEAN management type and do not open explicitly a transaction context, no sync point would be available...

Spring Integration, JMS Inbound channel gateway and transactions

I am using SI configured with a jms:message-driven-channel-gateway . My use case is to receive a message from the queue, save it via JDBC to a database, commit the message from the queue, and then let this message continue to flow through the various channels depending on its type. If the message subsequently errors this is ok as I have the original stored in the database so it can be replayed.
My issue is with trying to commit the transaction from the queue immediately after the database persist. This is effectively mid flow and I have only been able to get the spring transaction management to try and commit right at the end. This is not suitable as if an error is thrown after the database persist it still leaves the message on the JMS queue, as this is where the outer transaction originated.
So, is there an easy way to pull the message from a JMS queue, save to database, then commit it off the queue ?
Thanks!
You need to go asynch after the DB commit - use an ExecutorChannel or a QueueChannel after the DB update; the downstream flow will then run on another thread and the transactions will commit after the handoff.

about Session.rollBack() in JMS

All,
i am new to JMS and i have a question about Session.rollBack() method in JMS. AFAIK, this method is used to roll back all operations to JMS server (sending/receiving) by the session when using *SESSION_TRANSACTED* acknowledge mode. Now suppose I am calling this method in a catch block of a receiving/processing operation (is reasonable?), to tell JMS server to redeliver the message for processing, But even if it is redelivered the processing still throws the same exception which cause the JMS server to redeliver the message again, so it seems a infinite process. How to handle this problem? or are there any other JMS features that is designed for it? Thanks in advance!
The rollback method in JMS will rollback any message sends and receives in that "transaction". Transaction here is local to the JMS session.
Whether a redelivery will cause a problem really depends on why the exception occurred. If it was due to some transitory issue then a redelivery may work. If you have the kind of problem that is once it occurs will always occur (an example of this would be a JMS TextMessage whose body should contain XML, but doesn't).
The JMS API doesn't provide any solution to this itself. This is typically taken care of by the JMS provider and how it behaves will depend on which one you use. WebSphere MQ for instance will redeliver up to a configurable maximum at which point it will move it off to a queue for bad messages. The Service Integration Bus in WebSphere Application Server has similar behaviour. I suggest you consult your JMS provider documentation to determine exactly how it behaves in this situation.
If you are running in an application server rollback typically doesn't do anything because the application server will be managing transactions for you.

JBoss doesn't sends a JmsTemplate (Spring) message

Well, actually JBoss does send the message, but only when the current transaction started by the EJB is finished.
We have this problem with JBoss 4.0.3 and Spring's JmsTemplate. An EJB sends a message to a queue with a temporary queue as the reply_to field. Then, inside the same transaction, we listen for the response given by the first MDB. The problem is that the JmsTemplate's method "send" isn't executed after the transaction have finished. So, by the time the message is sent to the queue, and processed by the MDB, the listener of the temporary queue is gone.
This is called "Synchronous Reception"
Two things change this behavior but does raise some concerns:
Change the EJB's transaction type to BMT. (Concern: BMT sucks)
Create a thread that all it does is to call the JmsTemplate.send() method.
As a side note, this is an EJB that is working correctly on a weblogic environment, and the message does get sent when it should, in the middle of the transaction not when it's over.
Thanks for any help.
JBoss's behaviour is correct. JMS is a transactional API, and sends should only be executed when the tx commits.
It may be possible to convince JmsTemplate not use the current transactional context, although it makes a point of trying to hide the unpleasantness of the JMS API from you.
You could wrap the JMS template in code, either a Stateless session bean or a service method using Spring's transaction management, that uses a transaction propagation of REQUIRES_NEW. That way the sending of the message is in its own transaction that will commit the sending of the message outside the scope of the wrapping transaction.
I'm not sure why this would work on Weblogic though. My guess would be that on Weblogic it's not recognizing the queue as an XA Queue.

Resources