Unacked message if RabbitMQ server restarts in between the consumer consumes message - java

I am using Spring AMQP and this is my connection factory code:
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setAcknowledgeMode(AcknowledgeMode.AUTO);<br/>
factory.setDefaultRequeueRejected(false);
During consuming the message if RabbitMQ server restarts or there is a connection lost I will get the below exception:
org.springframework.amqp.rabbit.connection.AutoRecoverConnectionNotCurrentlyOpenException: Auto recovery connection is not currently open
If server comes up my application will be connected again
but with a new connection and there will be an unacked messsage.
How to handle this? I want the message to be requeued and my old connection should be killed.

Consider to use the latest Spring AMQP 1.7.2 which turns off that:
connectionFactory.setAutomaticRecoveryEnabled(false);
on the target com.rabbitmq.client.ConnectionFactory in favor of its own recovery mechanism.

Related

Quarkus ActiveMQ JMS

I have an ActiveMQ queue that does seem not seem to be supported by Quarkus. When I try to use the Quarkus JMS implementation described here I get the following error:
AMQP SASL header mismatch value 0, expecting 41. In state: HEADER0
I assume that this is because the ActiveMQ server does not support AMQP. The code I wrote to try and connect to the ActiveMQ server.
ConnectionFactory connectionFactory = new ConnectionFactory();
connection = connectionFactory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue("inQue");
producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
messageMap = session.createMapMessage();
While the above does not work. If i change it to using
ActiveMQConnectionFactory from ActiveMQ it works just fine:
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");
connection = connectionFactory.createConnection("admin", "admin");
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue("inQue");
producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
messageMap = session.createMapMessage();
But if i change to the Quarkus version of ConnectionFactory it no longer works and I get the error above. So is it possible to solve this somehow? Or do I need to use ActiveMQConnectionFactory? If so, how can I get Quarkus to register my MessageListener? Right now, just to test, I write:
MessageListener listener = new MyListener();
consumer.setMessageListener(listener);
But I would like Quarkus to do this when the application starts. But I'm not sure how to do it.
Depending on which version of ActiveMQ you are using you should be able to use the Quarkus JMS extension which is based on Qpid JMS and speaks AMQP. The trick is that you need to connect to the transport connector that was configured to speak AMQP and not one that uses the native Openwire protocol which normally resides on port 61616.
The ActiveMQ documentation defines how this is done. Essentially in your broker configuration you need a definition similar to this:
<transportConnectors>
<transportConnector name="amqp" uri="amqp://0.0.0.0:5672"/>
</transportConnectors>
Of course if using ActiveMQ Artemis this configuration would be different but you didn't specify which specific version of ActiveMQ you are running.
The error message you provided (If it is from the server logs) indicates that the client did indeed connect to an AMQP endpoint but it got something that it did not expect which implies something else strange is going on such as you are not using Qpid JMS but some other client since the initial byte of the expected AMQP header is reported to have been zero which is definitely wrong since an AMQP header always starts with the letter 'A'.
NOTE: Given the comments the error message in the question is likely from the client which would indicate the client read the normally sent Openwire header meaning the transport connector in play was an Openwire variant.

Avoiding error messages in connecting to active/passive ActiveMQ

I am creating a program to send messages to ActiveMQ. This server is in active/passive configuration with one active and two standby nodes.
My code for creating connections as follows:
String furl = "failover:(tcp://aa.myamq-01:61616:tcp://aa.myamq-02:61616:tcp://aa.myamq-03:61616");
ConnectionFactory = new ActiveMQConnectionFactory(furl);
Connection connection = ConnectionFactory.createConnection();
connection.start();
Everything works as expected. However I get the following output in the console.
ERROR | Connect fail to tcp://aa.myamq-01:61616, error message : Connection refused:Connect
ERROR | Connect fail to tcp://aa.myamq-02:61616, error message : Connection refused:Connect
INFO |Successfully connected to tcp://aa.myamq-03:61616
Is there a way the active server can be identified and connection attempted to it only? Alternatively, can the error messages be suppressed?
AFAIK there isn't in this scenario. Inactive ActiveMQ nodes are actually not accepting connections. Therefor they look like they are down.
But if you would need to find out which node is master you can find that in DB if you use DB backend in ActiveMQ.
Regarding suppressing this message I would not even try to do that because if there would be a regular failure you will not notice it.

How to timeout queueConnectionFactory create connection

I'm facing a timeout while invoking javax.jms.QueueConnectionFactory.createQueueConnection()
¿Is there any way to customize timout time for creating connection?
javax.jms.QueueConnectionFactory connectionFactory; //look up in context here
connectionFactory.createConnection();
This depends to how you connect to jms, for spring you can see How to set waiting timeout on JmsMessagingTemplate.sendAndReceive for ibm mq IBM MQ Connect Factory CLIENTRECONNECTTIMEOUT without using CLIENTRECONNECTOPTIONS

Jms Broker connection - Test the connection before listening to the queue - java

We have a message listener that listens to the Queue configured. When the Message broker is stopped or down, the application exits abruptly. Is there way to check the JMS broker connection before listening to the queue. The listener code must be enabled only if the JMS Broker is up. We are getting the below exception when we listen to the Queue (with the JMS broker down)
org.springframework.context.ApplicationContextException: Failed to start bean 'xx'; nested exception is org.springframework.jms.UncategorizedJmsException: Uncategorized exception occured during JMS processing; nested exception is javax.jms.JMSException: Could not connect to broker URL: tcp://xx:61616. Reason: java.net.ConnectException: Connection refused: connect
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:176)
at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:51)
at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:346)
at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:149)
at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:112)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:773)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.finishRefresh(EmbeddedWebApplicationContext.java:142)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:485)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:120)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:952)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:941)
you can not test your connection to be active, as whenever you setup connection with activemq it only succeeds if you have an activemq server running.
A good option can be to do it in Java code by handling 'connection exceptions' and trying to re-connect after specific intervals till no exception occurs.This will help in scenario where ActiveMQ is down before you try and setup connection with it.
Hope it helps,
Good Luck!
Use the failover transport in your clients: failover:(tcp://host:port?TCP_OPTIONS)?FAILOVER_OPTIONS
When the connection isn't available (via the inner TCP transport), the failover transport will continue retrying until it is available and then establish the connection and let your client proceed as normal. This will look like the client is hung, but it's just waiting for the broker to become available before continuing. This configuration will also try to re-connect if the connection is broken for some reason (e.g. you restart your broker).
Most people use the failover transport to allow you to connect to whichever broker out of a group of N is available, but it's completely fine to use it with just one inner TCP transport; it will still try to reconnect periodically whenever it fails to connect to the single TCP transport.

Weblogic jms distributed topic

Using java application, I'm trying to create a durable subscription on a jms uniform distributed topic.
The jms server is running on weblogic 10.3.5 and the topic is distributed on 2 servers.
If I'm developping a message driven bean, it's working. I have a durable subscription on both servers with the same subscription name.
With a standalone java application, I can do the job with a normal topic (not distributed). But can't manage it to work with distributed topic.
InitialContext ic = new InitialContext();
TopicConnectionFactory connectionFactory = (TopicConnectionFactory) ic.lookup("myConnectionFactory");
TopicConnection connection = connectionFactory.createTopicConnection();
connection.setClientID("testclient");
TopicSession session = connection.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);
TopicSubscriber subscriber;
Topic topic1 = (Topic) ic.lookup("jmsserver1#myTopic");
Topic topic2 = (Topic) ic.lookup("jmsserver2#myTopic");
subscriber = session.createDurableSubscriber(topic1,"testSubscription","",false);
subscriber = session.createDurableSubscriber(topic2,"testSubscription","",false);
Gives me
Exception in thread "main" weblogic.jms.common.JMSException: [JMSClientExceptions:055037]Subscription testSubscription is in use
In the weblogic console the first subscription testSubscription on myJmsModule!jmsserver1#myTopic is created not the second.
What can I do ?
You will have to remove the durable subscription manually and WLS will not remove to automatically
https://docs.oracle.com/cd/E17904_01/web.1111/e15493/dist_topics.htm#WLMDB10013
Setting Automatic Deletion of Durable Subscriptions :-
You can configure an MDB to automatically delete a durable topic subscription when the MDB is undeployed or deleted from a server. To configure an MDB to automatically delete durable topic subscriptions, set durable-subscription-deletion to True. By default, durable-subscription-deletion is set to False
By default it is false and thus it will not clear the durable subscriber automatically.
You need to change the ConnectionFactory via the weblogic admin console to create shareable connections
Client ID Policy: CLIENT_ID_POLICY_UNRESTRICTED
Subscription Sharing Policy:Sharable
https://docs.oracle.com/cd/E57014_01/wls/WLACH/pagehelp/JMSjmsconnectionjmsconnectionfactoryconfigclientparamstitle.html

Categories

Resources