I am listening to a queue of activemq.
My configuration is like below:
ACTIVEMQ_BROKER_URL =failover:(tcp://LON6QAEQTAPP01:61616?wireFormat.maxInactivityDuration=0)
From the console logs I can see that a reconnect attempt is made to connect to this server.
[2014-08-20 08:57:43,303] INFO 236[ActiveMQ Task-1] -
org.apache.activemq.transport.failover.FailoverTransport.doReconnect(FailoverTransport.java:1030)
- Successfully connected to tcp://LON6QAEQTAPP01:61616?wireFormat.maxInactivityDuration=0
[2014-08-20 08:57:43,355] INFO 288[ActiveMQ Task-1] -
org.apache.activemq.transport.failover.FailoverTransport.doReconnect(FailoverTransport.java:1030)
- Successfully connected to tcp://LON6QAEQTAPP01:61616?wireFormat.maxInactivityDuration=0
[2014-08-20 08:57:43,374] INFO 307[ActiveMQ Task-1] -
org.apache.activemq.transport.failover.FailoverTransport.doReconnect(FailoverTransport.java:1030)
- Successfully connected to tcp://LON6QAEQTAPP01:61616?wireFormat.maxInactivityDuration=0
Still I am not able to consume the message. I am using the following code to try and handle it from code side but still not able to get the connection persistent.
try
{
connection.start();
while (true)
{
try
{
if (connection.isClosed() || connection.isTransportFailed() || session.isClosed() || !connection.getTransport().isConnected())
{
log.info("Connection was reset, re-connecting..");
connection.cleanup();
init();
connection.start();
}
}
catch (Throwable t)
{
init();
log.error("Connection was reset, re-connecting in exception block", t);
}
Thread.sleep(30000L);
}
private void init() throws Exception
{
init(brokerURL, queueName, userName, password, manual);
}
public void init(String brokerURL, String queueName, String userName, String password, boolean manual) throws Exception
{
this.manual = manual;
this.brokerURL = brokerURL;
this.queueName = queueName;
this.userName = userName;
this.password = password;
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(userName, password, brokerURL);
connection = (ActiveMQConnection) connectionFactory.createConnection();
connection.addTransportListener(new TransportListener()
{
#Override
public void transportResumed()
{
log.info("Transport Resumed ");
}
#Override
public void transportInterupted()
{
log.info("Transport Interupted ");
}
#Override
public void onException(IOException arg0)
{
arg0.printStackTrace();
log.error("Transport Exception: " + arg0.getMessage());
}
#Override
public void onCommand(Object arg0)
{
// TODO Auto-generated method stub
}
});
connection.setExceptionListener(this);
connection.setCloseTimeout(10);
session = (ActiveMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE);// CLIENT_ACKNOWLEDGE
Destination destination = session.createQueue(queueName);
MessageConsumer consumer = session.createConsumer(destination);
consumer.setMessageListener(this);
}
Can someone help me as to how can I get this connection to be active alive all the time. It generally times out after inactivity of 40 mins or so.
Trying to force reconnect an open connection the way you are is definitely not going to do you and good. You need to tear down the connection and create a new one if you want to handle connection interruption yourself. What you really should do is figure out what is closing your connection on you, probably a firewall closing down the inactive connection or a load balancer. Look at your environment and see what else is in the mix that could be closing the connection on you.
The broker can, if configured to do so, rebalance clients in a cluster. Are you using multiple clients in a clustered environment etc?
Related
I have this method that throws me an exception when the data queue doesn't exists, but is not. Do you have other way to solve this?
public void checkDataQueue(String dataQueue) throws JMSException {
Connection connection = null;
Session session = null;
connection = jmsTemplate.getConnectionFactory().createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue(dataQueue);
QueueBrowser browser = session.createBrowser(queue);
}
ActiveMQ 5.x creates Queues on demand by default so you may have changed the default configuration to disallow this in which case the error should be expected to happen if you are hitting a non-existent queue and you should check for and handle that. If you need to be sure then the broker provides a JMX interface to query for information on broker statistics etc. There are also other ways of monitoring such as using Rest style calls over the Jolokia management interface.
thank you Tim, I solved it with these method.
public boolean existDataQueue(String dataQueue) throws JMSException {
boolean response = false;
ActiveMQConnectionFactory activeMQConnectionFactory =
new ActiveMQConnectionFactory();
activeMQConnectionFactory.setBrokerURL(brokerUrl);
ActiveMQConnection connection = (ActiveMQConnection)activeMQConnectionFactory.createConnection();
connection.start();
DestinationSource ds = connection.getDestinationSource();
Set<ActiveMQQueue> queues = ds.getQueues();
for (ActiveMQQueue activeMQQueue : queues) {
try {
if(activeMQQueue.getQueueName().equalsIgnoreCase(dataQueue)) {
response = true;
}
} catch (JMSException e) {
e.printStackTrace();
}
}
connection.close();
return response;
}
I have a small spring-boot app set up that connects to one or more Topics on ActiveMQ, which are set in the application's application.properties file on startup - and then sends these messages on to a database.
This is all working fine, but I am having some problems when trying to implement a failover - basically, the app will try to reconnect, but after a certain number of retries, the application process will just automatically exit, preventing the retry (ideally, I would like the app to just retry forever until killed manually or ActiveMQ becomes available again). I have tried explicitly setting the connection options (such as maxReconnectAttempts) in the connection URL (using url.options in application.properties) to -1/0/99999 but none of these seem to be right as the behavior is the same each time. From looking at the advice on Apache's own reference page I would also expect this behavior to be working as default too.
If anyone has any advice to force the app not to quit, I would be very grateful! The bits of my code that I think will matter is below:
#Configuration
public class AmqConfig {
private static final Logger LOG = LogManager.getLogger(AmqConfig.class);
private static final String LOG_PREFIX = "[AmqConfig] ";
private String clientId;
private static ArrayList<String> amqUrls = new ArrayList<>();
private static String amqConnectionUrl;
private static Integer numSubs;
private static ArrayList<String> destinations = new ArrayList<>();
#Autowired
DatabaseService databaseService;
public AmqConfig (#Value("${amq.urls}") String[] amqUrl,
#Value("${amq.options}") String amqOptions,
#Value("${tocCodes}") String[] tocCodes,
#Value("${amq.numSubscribers}") Integer numSubs,
#Value("${clientId}") String clientId) throws UnknownHostException {
Arrays.asList(amqUrl).forEach(url -> {
amqUrls.add("tcp://" + url);
});
String amqServerAddress = "failover:(" + String.join(",", amqUrls) + ")";
String options = Strings.isNullOrEmpty(amqOptions) ? "" : "?" + amqOptions;
this.amqConnectionUrl = amqServerAddress + options;
this.numSubs = Optional.ofNullable(numSubs).orElse(4);
this.clientId = Strings.isNullOrEmpty(clientId) ? InetAddress.getLocalHost().getHostName() : clientId;
String topic = "Consumer." + this.clientId + ".VirtualTopic.Feed";
if (tocCodes.length > 0){
Arrays.asList(tocCodes).forEach(s -> destinations.add(topic + "_" + s));
} else { // no TOC codes = connecting to default feed
destinations.add(topic);
}
}
#Bean
public ActiveMQConnectionFactory connectionFactory() throws JMSException {
LOG.info("{}Connecting to AMQ at {}", LOG_PREFIX, amqConnectionUrl);
LOG.info("{}Using client id {}", LOG_PREFIX, clientId);
ActiveMQConnectionFactory connectionFactory =
new ActiveMQConnectionFactory(amqConnectionUrl);
Connection conn = connectionFactory.createConnection();
conn.setClientID(clientId);
conn.setExceptionListener(new AmqExceptionListener());
conn.start();
destinations.forEach(destinationName -> {
try {
for (int i = 0; i < numSubs; i++) {
Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue(destinationName);
MessageConsumer messageConsumer = session.createConsumer(destination);
messageConsumer.setMessageListener(new MessageReceiver(databaseService, destinationName));
}
} catch (JMSException e) {
LOG.error("{}Error setting up queue # {}", LOG_PREFIX, destinationName);
LOG.error(e.getMessage());
}
});
return connectionFactory;
}
}
public class MessageReceiver implements MessageListener, ExceptionListener {
public static final Logger LOG = LogManager.getLogger(MessageReceiver.class);
private static final String LOG_PREFIX = "[Message Receiver] ";
private DatabaseService databaseService;
public MessageReceiver(DatabaseService databaseService, String destinationName){
this.databaseService = databaseService;
LOG.info("{}Creating MessageReceiver for queue with destination: {}", LOG_PREFIX, destinationName);
}
#Override
public void onMessage(Message message) {
String messageText = null;
if (message instanceof TextMessage) {
TextMessage tm = (TextMessage) message;
try {
messageText = tm.getText();
} catch (JMSException e) {
LOG.error("{} Error getting message from AMQ", e);
}
} else if (message instanceof ActiveMQMessage) {
messageText = message.toString();
} else {
LOG.warn("{}Unrecognised message type, cannot process", LOG_PREFIX);
LOG.warn(message.toString());
}
try {
databaseService.sendMessageNoResponse(messageText);
} catch (Exception e) {
LOG.error("{}Unable to acknowledge message from AMQ. Message: {}", LOG_PREFIX, messageText, e);
}
}
}
public class AmqExceptionListener implements ExceptionListener {
public static final Logger LOG = LogManager.getLogger(AmqExceptionListener.class);
private static final String LOG_PREFIX = "[AmqExceptionListener ] ";
#Override
public void onException(JMSException e){
LOG.error("{}Exception thrown by ActiveMQ", LOG_PREFIX, e);
}
}
The console output I get from my application is just the below (apologies, as it is not much to go off)
[2019-12-12 14:43:30.292] [WARN ] Transport (tcp://[address]:61616) failed , attempting to automatically reconnect: java.io.EOFException
[2019-12-12 14:43:51.098] [WARN ] Failed to connect to [tcp://[address]:61616] after: 10 attempt(s) continuing to retry.
Process finished with exit code 0
Very interesting Question!
Configuring the maxReconnectAttempts=-1 will cause the connection attempts to be retried forever, but what I feel the problem here are as follows:
You are trying to connect to ActiveMQ while creating the Bean at App
startup, If ActiveMQ is not running when APP is starting up, the
Bean creation would retry the connection attempts forever causing a
timeout and not letting the APP to start.
Also when the ActiveMQ stops running midway you are not reattempting the connection as it is done inside #Bean and will only happen on APP startup
Hence the Connection shouldn't happen at Bean creation time, but maybe it can be done after the APP is up (maybe inside a #PostConstruct block)
These are just the pointers, You need to take it forward
Hope this helps!
Good luck!
Hi am working on wso2 esb and using Active MQ for message queue.
I have a simple service to place a message in which it call custom java class where it creates a tcp connection and drops a message in queue.
Java code looks like below
package in.esb.custommediators;
import javax.jms.*;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.synapse.ManagedLifecycle;
import org.apache.synapse.MessageContext;
import org.apache.synapse.core.SynapseEnvironment;
import org.apache.synapse.mediators.AbstractMediator;
import org.apache.synapse.core.axis2.Axis2MessageContext;
import org.apache.synapse.transport.nhttp.NhttpConstants;
import org.json.JSONObject;
import org.json.XML;
public class JMSStoreMediator extends AbstractMediator implements
ManagedLifecycle {
Connection connection;
Session session;
public boolean mediate(MessageContext msgCtx) {
log.info("LogLocation = "+getClass().getName()+",ProxyName = "+msgCtx.getProperty("proxy.name")+
",Usercode = "+msgCtx.getProperty("usercode")+",Clientid = "+msgCtx.getProperty("clientid")+
",requestMsgId = "+msgCtx.getProperty("requestMsgId")+",Position = START");
try {
boolean topic=false;
String jmsuri=""+msgCtx.getProperty("jmsuri");
String t=""+msgCtx.getProperty("topic");
if(t.isEmpty()){
topic=false;
}
else {
topic=Boolean.valueOf(t);
}
ConnectionFactory factory= new ActiveMQConnectionFactory(jmsuri);
connection = factory.createConnection();
connection.start();
log.info("LogLocation = "+getClass().getName()+",JMS connection created :"+connection);
this.session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination=null;
if(!topic)destination= session.createQueue(""+msgCtx.getProperty("jmsqueue"));
else destination= session.createTopic(""+msgCtx.getProperty("jmsqueue"));
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
String xml = ""+msgCtx.getEnvelope().getBody().toStringWithConsume();
if(topic){
JSONObject obj=XML.toJSONObject(xml);
JSONObject ar=obj.getJSONObject("soapenv:Body");
ar.remove("xmlns:soapenv");
xml=ar.toString();
}
TextMessage message = session.createTextMessage(xml);
producer.send(message);
} catch (Exception e) {
log.info("LogLocation = "+getClass().getName()+",Error in storing message in JMS stacktrace is :"+e.toString()+"message is :"+e.getMessage());
e.printStackTrace();
((Axis2MessageContext) msgCtx).setProperty(NhttpConstants.HTTP_SC, 500);
handleException("Error while storing in the message store", msgCtx);
}
finally {
try {
session.close();
if (connection!=null){
log.info("LogLocation = "+getClass().getName()+",JMS connection closing :"+connection);
connection.close();
}
} catch (JMSException e) {
log.info("LogLocation = "+getClass().getName()+",Error in closing JMS connection stacktrace is :"+e.toString());
e.printStackTrace();
}
}
return true;
}
#Override
public void destroy() {
// TODO Auto-generated method stub
}
#Override
public void init(SynapseEnvironment arg0) {
// TODO Auto-generated method stub
}
}
when i call this service to send a message in queue below logs get generated.
[2017-07-29 11:18:35,962] INFO - JMSStoreMediator LogLocation = in.esb.custommediators.JMSStoreMediator,JMS connection created :ActiveMQConnection {id=ID:my-desktop-36442-1501307315570-3:1,clientId=ID:my-desktop-36442-1501307315570-2:1,started=true}
As of now every thing is working good , But when two users try to submit message at the same tire some strange thing happen as shown below
[2017-07-29 11:43:11,948] INFO - JMSStoreMediator LogLocation = in.my.esb.custommediators.JMSStoreMediator,JMS connection created :ActiveMQConnection {id=ID:my-desktop-36442-1501307315570-11:1,clientId=ID:my-desktop-36442-1501307315570-10:1,started=false}
[2017-07-29 11:43:11,963] INFO - JMSStoreMediator LogLocation = in.my.esb.custommediators.JMSStoreMediator,JMS connection created :ActiveMQConnection {id=ID:my-desktop-36442-1501307315570-11:1,clientId=ID:my-desktop-36442-1501307315570-10:1,started=true}
[2017-07-29 11:43:12,068] INFO - JMSStoreMediator LogLocation = in.my.esb.custommediators.JMSStoreMediator,Error in closing JMS connection stacktrace is :org.apache.activemq.ConnectionClosedException: The connection is already closed
Active MQ is creating two connections but using one connection for both the calls and that one connection is getting closed in one of the service call and throwing already closed error in the other service call and the other connection is waiting forever in the connection list of active mq with active status true as shown in the below image and this is also seen in the ESB thread list.
This kind of connections pileup and causing hangs ESB server. Even if i reset this connections from Active MQ ESB threads carry this connection info and only after a restart of ESB the problem get fixed.
Have you read article Extending the Functionality of WSO2 Enterprise Service Bus - Part 1 ?
Important part is Threading Safety. It states, each mediator, including custom, is shared between incoming messages. I recommend to move class variables
Connection connection;
Session session;
to method public boolean mediate(MessageContext msgCtx) since local variables are thread safe
public class JMSStoreMediator extends AbstractMediator implements
ManagedLifecycle {
public boolean mediate(MessageContext msgCtx) {
Connection connection;
Session session;
....
....
rest the same
I am looking to extend AbstractJavaSamplerClient so that I can fire messages to RabbitMQ. The current setup I have is:
Have connection and channel objects as instance members
Create the connection and channel connection in setupTest()
Send the messages in runTest()
Clean up the connection in teardownTest()
Code:
package com.the.package.samplers.TheSampler
import ...
...
public final class TheSampler extends AbstractJavaSamplerClient {
private final ConnectionFactory factory = new ConnectionFactory();
private Connection connection = null;
private Channel channel = null;
...
#Override
public Arguments getDefaultParameters() {
Arguments parameters = new Arguments();
...
return parameters;
#Override
public void setupTest(JavaSamplerContext context) {
...
factory.setHost(host);
factory.setVirtualHost(vhost);
factory.setPort(port);
factory.setUsername(username);
factory.setPassword(password);
routingKey = queue;
try {
connection = factory.newConnection();
channel = connection.createChannel();
channel.exchangeDeclare(exchange, EXCHANGE_TYPE, true);
channel.queueDeclare(queue, true, false, false, null);
channel.queueBind(queue, exchange, routingKey);
}
catch(IOException e) {
...
}
}
#Override
public SampleResult runTest(JavaSamplerContext context) {
...
channel.basicPublish(exchange, routingKey, null, message.getBytes());
...
}
#Override
public void teardownTest(JavaSamplerContext context) {
try {
channel.close();
connection.close();
}
catch(IOException e) {
...
}
}
}
After running the JMeter test with 5 threads for some time, the message rate drops and I start seeing the following exception (repeated indefinitely):
ERROR - jmeter.threads.JMeterThread: Error while processing sampler 'Java Request' : com.rabbitmq.client.AlreadyClosedException: connection is already closed due to connection error; cause: java.net.SocketException: Connection reset
at com.rabbitmq.client.impl.AMQChannel.ensureIsOpen(AMQChannel.java:190)
at com.rabbitmq.client.impl.AMQChannel.transmit(AMQChannel.java:291)
at com.rabbitmq.client.impl.ChannelN.basicPublish(ChannelN.java:647)
at com.rabbitmq.client.impl.ChannelN.basicPublish(ChannelN.java:630)
at com.rabbitmq.client.impl.ChannelN.basicPublish(ChannelN.java:621)
at com.the.package.samplers.TheSampler.runTest(TheSampler.java:102)
at org.apache.jmeter.protocol.java.sampler.JavaSampler.sample(JavaSampler.java:191)
at org.apache.jmeter.threads.JMeterThread.process_sampler(JMeterThread.java:434)
at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:261)
at java.lang.Thread.run(Unknown Source)
I tried to be a bit more safe by creating and closing the connection and channel objects in runTest(), but that incurred a huge performance hit (fires at a max of 50 messages per second, and previously was in the thousands).
Is there a way to safely create a connection to RabbitMQ when extending AbstractJavaSamplerClient and running with multiple threads?
I don't see any issue in your code from what you show.
Where is JMeter located regarding rabbitmq server ? ie is there a firewall between them ?
You should check this:
https://www.rabbitmq.com/reliability.html
Detecting Dead TCP Connections with Heartbeats
I am using JMS with JBoss. But whenever i run the my consumer code i always get the below exception
[org.jboss.as.naming] (Remoting "sorabh216901" task-2) JBAS011806: Channel end notification received, closing channel Channel ID 091878ba (inbound) of Remoting connection 007ce8a6 to /192.168.2.47:53318
My Consumer class is as below:
public class TopicConsumer implements MessageListener{
public static void main(String[] args) throws NamingException, JMSException {
Context context = TopicConsumer.getInitialContext();
try{
System.out.println("Entering into the main method!!!");
TopicConnectionFactory connectionFactory = (TopicConnectionFactory) context.lookup("jms/RemoteConnectionFactory");
Topic topic = (Topic) context.lookup("jms/topic/test");
TopicConnection connection = connectionFactory.createTopicConnection("testuser", "testpassword");
TopicSession session = connection.createTopicSession(true, TopicSession.AUTO_ACKNOWLEDGE);
session.createSubscriber(topic).setMessageListener(new TopicConsumer());
connection.start();
System.out.println("Exiting from the main method!!!");
}finally{
//context.close();
}
}
public void onMessage(Message arg0) {
System.out.println("Incoming Message : " + arg0);
}
public static Context getInitialContext() throws NamingException{
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
props.put("remote.connection.default.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS", "JBOSS-LOCAL-USER");
props.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
props.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false");
props.put(Context.PROVIDER_URL,"remote://192.168.2.47:4447");
props.put("jboss.naming.client.ejb.context", true);
// username
props.put(Context.SECURITY_PRINCIPAL, "testuser");
// password
props.put(Context.SECURITY_CREDENTIALS, "testpassword");
return new InitialContext(props);
}
}
When ever i ran the code i get the successful handshake in logs i.e.
INFO: EJBCLIENT000013: Successful version handshake completed for receiver context EJBReceiverContext{clientContext=org.jboss.ejb.client.EJBClientContext#cd0d2e,
receiver=Remoting connection EJB receiver [connection=Remoting connection <1e03fce>,channel=jboss.ejb,nodename=sorabh216901]} on channel Channel ID 9823d1ac (outbound) of Remoting connection 004edf4a to /192.168.2.47:4447
But the program just closed and in server logs i get channel end notification.
Please suggest, what is wrong here.
Add the following line at the end of main method of TopConsumer
class:
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
This will not stop the JVM. And you won't get Channel End Notification exception