JMS - producer is closed - jms

The following code is trying to send a message on a queue using JMS.
connection = jmsConnectionFactory.createConnection();
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue(queueName);
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
It works most of the time but while running a stress tests where many messages were sent in parallel, I found once the exception below:
Caused by: javax.jms.IllegalStateException: The producer is closed
at org.apache.activemq.ActiveMQMessageProducer.checkClosed(ActiveMQMessageProducer.java:195)
at org.apache.activemq.ActiveMQMessageProducerSupport.setDeliveryMode(ActiveMQMessageProducerSupport.java:136)
The exception is thrown in the setDeliveryMode().
I have seen other posts about the same issue, but in my case I am not using shared sessions, nor shared connections.
I am running ActiveMQ 5.14.5.

Looking at the code for org.apache.activemq.ActiveMQMessageProducer the closed variable (which is checked by the checkClosed() method at the top of the stack-trace) is initialized as false so something else has to be setting it to true for this exception to be thrown. From what I can see it is only set to true when the producer itself, the originating session, or originating connection is closed. It's possible that the connection and/or session is being closed in the background due to some other failure and this exception with the producer is the first visible symptom of that problem.
In any case, without at least some additional details about your code or ideally a minimal, reproducible example it's not really possible to draw a reliable conclusion.

Related

Apache Qpid JMS client message producer getting stuck and not delivering to queue

I am trying to send a message to the Qpid broker over the AMQP 1.0 protocol. The queue is named queue2 and it is already created under default virtualhost. However, producer.send(message) is getting stuck forever. The same code is working for connecting to Azure Service Bus. I'm using qpid-jms-client 0.58. Producer code is:
Hashtable<String, String> hashtable = new Hashtable<>();
hashtable.put("connectionfactory.myFactoryLookup", protocol + "://" + url + "?amqp.idleTimeout=120000&amqp.traceFrames=true");
hashtable.put("queue.myQueueLookup", queueName);
hashtable.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.qpid.jms.jndi.JmsInitialContextFactory");
Context context = new InitialContext(hashtable);
ConnectionFactory factory = (ConnectionFactory) context.lookup("myFactoryLookup");
queue = (Destination) context.lookup("myQueueLookup");
Connection connection = factory.createConnection(username, password);
connection.setExceptionListener(new AmqpConnectionFactory.MyExceptionListener());
connection.start();
Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// session.createQueue("queue3");
Queue queue = new JmsQueue("queue2");
MessageProducer messageProducer = session.createProducer(queue);
TextMessage textMessage = session.createTextMessage("new message");
messageProducer.send(textMessage)
I can see Connection and session is successfully established on Qpid broker dashboard:
Thread dump for application at time of producing
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000078327c550> (a org.apache.qpid.jms.provider.ProgressiveProviderFuture)
at java.lang.Object.wait(Object.java:502)
at org.apache.qpid.jms.provider.ProgressiveProviderFuture.sync(ProgressiveProviderFuture.java:154)
- locked <0x000000078327c550> (a org.apache.qpid.jms.provider.ProgressiveProviderFuture)
at org.apache.qpid.jms.JmsConnection.send(JmsConnection.java:773)
at org.apache.qpid.jms.JmsNoTxTransactionContext.send(JmsNoTxTransactionContext.java:37)
at org.apache.qpid.jms.JmsSession.send(JmsSession.java:964)
at org.apache.qpid.jms.JmsSession.send(JmsSession.java:843)
at org.apache.qpid.jms.JmsMessageProducer.sendMessage(JmsMessageProducer.java:252)
at org.apache.qpid.jms.JmsMessageProducer.send(JmsMessageProducer.java:182)
I have tried to run this example which gave the same result.
In general if the client is not sending it is because the remote has not granted it credit to do so. You can debug the client state using the protocol trace feature (just set PN_TRACE_FRM=true and run the client).
Likely you have misconfigured the Broker-J somehow and the destination you've created doesn't allow any messages to be sent or you've sent enough that you've tripped the write limit. You should consult the configuration guide and review what you've already setup.
Okay Finally got the issue. Filesystem is over 90 per cent full, enforcing flow control. So deleted files from my machine and it started working.
https://qpid.apache.org/releases/qpid-broker-j-7.0.7/book/Java-Broker-Runtime-Disk-Space-Management.html

IBM XMS.Net Listener Hangs Out when connection is closed forbiddenly

Hi I use webpshere mq client 8.0.0.8 and I set my listener at once and start to listen mq,but something went wrong and and myconnection is closed but it throws no error and mylistener hang out and cant listen message.If its throws error I have a mechanism to catch and restart it but that time I failed.Is there any property set to avoid this issue?
I have exceptionlistener and reconnect options in my connectionproperties.But this is not directly work,I have a autoresetevent (receiveCompleteEvent)mechanism,only solution I can find set signal in exceptionlistener,and kill connection.In exception listener I can log connection error notifications but no automatic connection set,
connectionfactory.SetIntProperty(IBM.XMS.XMSC.WMQ_CLIENT_RECONNECT_OPTIONS, IBM.XMS.XMSC.WMQ_CLIENT_RECONNECT);
connectionfactory.SetIntProperty(IBM.XMS.XMSC.WMQ_CLIENT_RECONNECT_TIMEOUT, 150);
private void OnException(Exception ex)
{
QueueStatuslog.Error(String.Format("Unexpected error occured to connection:{0}", ex.ToString()));
try
{
if (receiveCompleteEvent != null)
{
QueueStatuslog.Error(String.Format("Due to connection error send stop signal:{0}", ex.ToString()));
receiveCompleteEvent.Set();
}
Exception, like connection related, will be thrown to application when application makes synchronous MQ API call, like consumer.receive or producer.send. If you are using message listener to receive messages, the message delivery is an asynchronous operation and messages are delivered on the message listener thread. So XMS can not throw exceptions on that thread. Hence it requires another thread, i.e. ExceptionListener to let the application know about any connection related issues.
You will need to setup ExceptionListener on connection and catch any exception thrown. When an exception is thrown, issue Connection.Stop, clean up and reinitialize message receive.
You can also look at using automatic client reconnection and this.

How can I fix a new activemq-artemis install blocking issue?

I've been tasked with evaluating activemq-artemis for JMS clients. I have RabbmitMQ experience, but none with activemq-artemis/JMS.
I installed artemis to my local machine, created a new broker per the instructions, and set it up as a windows service. The windows service starts and stops just fine. I've made no changes to the broker.xml file.
For my first test I'm trying to perform a JMS Queue produce/consume from a stand alone java program. I'm using the code from the Artemis User Manual in the Using JMS section, (without using JNDI):
TransportConfiguration transportConfiguration = new TransportConfiguration(NettyConnectorFactory.class.getName());
ConnectionFactory cf = ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF,transportConfiguration);
Queue orderQueue = ActiveMQJMSClient.createQueue("OrderQueue");
Connection connection = cf.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(orderQueue);
MessageConsumer consumer = session.createConsumer(orderQueue);
connection.start();
TextMessage message = session.createTextMessage("This is an order");
producer.send(message);
TextMessage receivedMessage = (TextMessage)consumer.receive();
System.out.println("Got order: " + receivedMessage.getText());
When I run this code, I get the following error:
WARN: AMQ212054: Destination address=jms.queue.OrderQueue is blocked. If the system is configured to block make sure you consume messages on this configuration.
My research hasn't been conclusive on if this is a server side setting, or having the producer send without blocking. I haven't been able to find a producer send method that has a blocking boolean, only persistence. Any ideas on where to focus? Thanks.
Edit: new address-setting element added to broker.xml dedicated to this Queue:
<address-setting match="jms.queue.OrderQueue">
<max-size-bytes>104857600</max-size-bytes>
<page-size-bytes>10485760</page-size-bytes>
<address-full-policy>PAGE</address-full-policy>
</address-setting>
I found this on further research in the user manual:
max-disk-usage The max percentage of data we should use from disks.
The System will block while the disk is full. Default=100
and in the log after service startup with no messages published yet:
WARN [org.apache.activemq.artemis.core.server] AMQ222210: Storage usage is beyond max-disk-usage. System will start blocking producers.
so I think no matter my address settings, it would start to block. Looking at the max-disk-usage setting in broker.xml, it was set to 90. Documentation default says 100, I set to that, no startup log warnings, and my test pub/sub code now works.
This warn message comes when address policy set to BLOCK and memory reached. Check address policy set in broker.xml. If it is set to BLOCK, change it to PAGE. Or consume pending messages from OrderQueue.
By default max-disk-usage value is set as 90(%) and if the remaining free space size is less than 10%, then this warn message will be shown and no messages will be received until you adjust the parameter or free up space beyond 10%.

Reconnecting with MQ - issues

I'm looking forward to implement a somewhat intelligent MQ comms module, which should be tolerant for the outages in the network connection. Basically it should try to reconnect each 5 seconds if connection was lost.
The problem is the following. I use the following code for reading:
queueMessage = new MQMessage();
queueMessage.Format = MQC.MQFMT_STRING;
queueGetMessageOptions = new MQGetMessageOptions();
queueGetMessageOptions.Options = MQC.MQGMO_SYNCPOINT + MQC.MQGMO_WAIT + MQC.MQGMO_FAIL_IF_QUIESCING;
queueGetMessageOptions.WaitInterval = 50;
producerQueue.Get(queueMessage, queueGetMessageOptions);
msg = queueMessage.ReadBytes(queueMessage.MessageLength);
(Of course I successfully connect to the queuemanager before etc.)
I got the following issue: when this routine runs, but at the time of .Get there's no connection, the code simply hangs and stays in the .Get.
I use a timer to see if there's a timeout (in theory even that shouldn't be necessary, is that right?) and at the timeout I try to reconnect. BUT when this timeout expires, I still see that the queuemanager reports that it's connected, while its clearly not (no physical connection is present anymore). This issue has popped up since I use SYNCPOINT, and I experience the same when I cut connection during writing, or in this case I try to force a Disconnect on the queuemanager. So please help, what settings shall I use to avoid getting stuck in Get and Put and rather have an MQException thrown or something controllable?
Thanks!
UPDATE: I used the following code to connect to the QueueManager.
Hashtable props = new Hashtable();
props.Add(MQC.HOST_NAME_PROPERTY, Host);
props.Add(MQC.PORT_PROPERTY, Port);
props.Add(MQC.CHANNEL_PROPERTY, ChannelInfo);
if(User!="") props.Add(MQC.USER_ID_PROPERTY, User);
if(Password!="") props.Add(MQC.PASSWORD_PROPERTY, Password);
props.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED);
queueManager = new MQQueueManager(QueueManagerName, props);
producerQueue = queueManager.AccessQueue(
ProducerQueueName,
MQC.MQOO_INPUT_AS_Q_DEF // open queue for input
+ MQC.MQOO_FAIL_IF_QUIESCING); // but not if MQM stopping
consumerQueue = queueManager.AccessQueue(
ConsumerQueueName,
MQC.MQOO_OUTPUT + MQC.MQOO_BROWSE + MQC.MQOO_INPUT_AS_Q_DEF // open queue for output
+ MQC.MQOO_FAIL_IF_QUIESCING); // but not if MQM stopping
Needless to say that normally the code works well. Read/Write, connect/disconnect works as it should, I only have to figure out the current issue.
Thanks!
What version of MQ are you using? For automatic reconnection to work the queue manager need to be at least at MQ v701 and MQ .NET client needs to be a MQ v7.1 level.
Assuming you are using MQ v7.1 .NET client, you need to specify reconnect option during connection create. You will need to enable reconnection by adding something like:
props.Add(MQC.CONNECT_OPTIONS_PROPERTY, MQC.MQCNO_RECONNECT);
Reconnection can be enabled/disabled from mqclient.ini file also.
But what is surprising is why the Get/Put are hanging when there is no network connection. Hope you are not connecting a queue manager running on the same machine as your application. There is no need to set any timer or something like that. You can issue MQ calls and if there is anything wrong with connection, an exception will be thrown.
Update:
I think you are referring to IsConnected property of MQQueueManager class. The documentation says the value of this property: "If true, a connection to the queue manager has been made, and is not known to be broken. Any calls to IsConnected do not actively attempt to reach the queue manager, so it is possible that physical connectivity can break, but IsConnected can still return true. The IsConnected state is only updated when activity, for example, putting a message, getting a message, is performed on the queue manager.
If false, a connection to the queue manager has not been made, or has been broken, or has been disconnected."
As you can see a True value does not mean the connection is still ON. My suggestion would be to call a method, Put/Get and handle any exception thrown.
Put/Get/Disconnect calls hanging appears to be a problem. My suggestion would be raise a PMR with IBM.

xa_commit failed when trying to commit jms transaction

We are trying to write a message to a broker queue. But the whole request fails when it tries to commit the JMS transaction & then it tries to rollback each subsequent time. We use oracle XA drivers. Not sure where to post this issue: MQ forums or Oracle forum. So thought would give a try here. Can someone help resolve this please.
Error:
[9/25/12 17:10:06:871 EDT] 0000003e XATransaction E J2CA0027E: An exception occurred while invoking commit on an XA Resource Adapter from dataSource JMS$QCF$JMSManagedConnection#23, within transaction ID {XidImpl: formatId(57415344), gtrid_length(36), bqual_length(54), data(00000139ff43ef2500000001000043106c82332ef6bc723402e84f341fb357080ddd4d1b00000139ff43ef2500000001000043106c82332ef6bc723402e84f341fb357080ddd4d1b000000010000000000000000000000000001)}: javax.transaction.xa.XAException: The method 'xa_commit' has failed with errorCode '-7'.
at com.ibm.mq.jmqi.JmqiXAResource.commit(JmqiXAResource.java:407)
at com.ibm.ejs.jms.JMSManagedSession$JMSXAResource.commit(JMSManagedSession.java:1702)
at com.ibm.ejs.j2c.XATransactionWrapper.commit(XATransactionWrapper.java:463)
at com.ibm.ws.Transaction.JTA.JTAXAResourceImpl.commit_one_phase(JTAXAResourceImpl.java:305)
at com.ibm.ws.Transaction.JTA.RegisteredResources.flowCommitOnePhase(RegisteredResources.java:2916)
at com.ibm.ws.Transaction.JTA.TransactionImpl.commitXAResources(TransactionImpl.java:2533)
at com.ibm.ws.Transaction.JTA.TransactionImpl.stage1CommitProcessing(TransactionImpl.java:1687)
at com.ibm.ws.Transaction.JTA.TransactionImpl.processCommit(TransactionImpl.java:1647)
at com.ibm.ws.Transaction.JTA.TransactionImpl.commit(TransactionImpl.java:1582)
at com.ibm.ws.Transaction.JTA.TranManagerImpl.commit(TranManagerImpl.java:247)
at com.ibm.ws.Transaction.JTA.TranManagerSet.commit(TranManagerSet.java:168)
at com.ibm.ws.Transaction.JTA.UserTransactionImpl.commit(UserTransactionImpl.java:293)
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1009)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:255)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1002)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:901)
at org.springframework.scheduling.commonj.DelegatingWork.run(DelegatingWork.java:61)
at com.ibm.ws.asynchbeans.J2EEContext$RunProxy.run(J2EEContext.java:264)
at java.security.AccessController.doPrivileged(Native Method)
at com.ibm.ws.asynchbeans.J2EEContext.run(J2EEContext.java:1137)
at com.ibm.ws.asynchbeans.WorkWithExecutionContextImpl.go(WorkWithExecutionContextImpl.java:195)
at com.ibm.ws.asynchbeans.CJWorkItemImpl.run(CJWorkItemImpl.java:187)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1560)
.
[9/25/12 17:10:06:880 EDT] 0000003e RegisteredRes W WTRN0052E: An attempt by the transaction manager to call one phase commit on a transactional resource has resulted in an XAER_RMFAIL error. The resource was com.ibm.ws.Transaction.JTA.JTAXAResourceImpl#1d07bf1#{XidImpl: formatId(57415344), gtrid_length(36), bqual_length(54), data(00000139ff43ef2500000001000043106c82332ef6bc723402e84f341fb357080ddd4d1b00000139ff43ef2500000001000043106c82332ef6bc723402e84f341fb357080ddd4d1b000000010000000000000000000000000001)}
[9/25/12 17:10:06:887 EDT] 0000003e DefaultMessag W org.springframework.jms.listener.DefaultMessageListenerContainer handleListenerSetupFailure Setup of JMS message listener invoker failed for destination 'queue:///RANDOM QUEUE?targetClient=1' - trying to recover. Cause: Heuristic completion: outcome state is mixed; nested exception is javax.transaction.HeuristicMixedException
Here's the cause and resolution
Quote-
The cause of these errors is usually the result of a WebSphere MQ
messaging provider JMS Connection being closed off by WebSphere
Application Server because the Aged timeout for the Connection has
expired.
Resolution-
To resolve this issue, ensure that the JMS Connection Factory being
used by the application has the Connection Pool property Aged timeout
set to zero. This will prevent JMS Connections being closed when they
are returned to the Free Pool, and so ensures that any outstanding
transactional work can be completed
It is sometimes also caused by the faulty DataDirect Driver and is reported and fixed by IBM, see this.
Earlier we had multiple JMS sessions. That was probably the cause of the issue in one of the environments. So we had to change to 2 diff. sessions & now it works!
Julian:
My scenario is slightly different from yours. Earlier we had:
A request message was put on the queue. This queue was picked up & processed. Then we saved to the DB & then generated another message & put it on another broker queue & then sent a response to the first message. All this was 1 flow.
Now we changed that to 2 diff. flows : Request --> Process --> Save to DB --> Reply
and then another flow to put on Broker queue.
Hope this helps

Resources