Occasionally when my Java program gets an internal error and terminates, the connection to the MQ channel remains established.
Strangely the java code is not running on my machine, but in MQ explorer, it is shown as connected .
Is there is any process/service running in my machine which I can terminate manually to close the connection ?
Can you tell me what is the likely reason for this ( i am using connection.close / channel.close and queue.close) and what could be the likely
Regards
Abhinav
Is there is any process/service running in my machine which I can
terminate manually to close the connection ?
You need to include try/catch logic in your code and when you have an issue, then in the catch clause, have your code call its cleanup logic (i.e. close queues and disconnect from the queue manager).
Can you tell me what is the likely reason for this ( i am using
connection.close / channel.close and queue.close) and what could be
the likely
Obviously, you are not and it conflicts with your earlier statement of:
when my Java program gets an internal error and terminates,
Therefore, add the appropriate try/catch logic and properly close queues and disconnect from the queue manager even when bad things go wrong in your program.
You can add below method in finally:
private void cleanUp() {
if (producer != null) {
try {
producer.close();
} catch (JMSException jmsex) {
logger.error("WebSphereMQMessageSender. cleanUp: Producer could not be closed.");
recordFailure(jmsex);
}
}
if (session != null) {
try {
session.close();
} catch (JMSException jmsex) {
logger.error("WebSphereMQMessageSender. cleanUp: Session could not be closed.");
recordFailure(jmsex);
}
}
if (connection != null) {
try {
connection.close();
} catch (JMSException jmsex) {
logger.error("WebSphereMQMessageSender. cleanUp: Connection could not be closed.");
recordFailure(jmsex);
}
}
}
for more information see this.
Related
The below program acts as TCP client and uses NIO to open socket to a remote server, as below
private Selector itsSelector;
private SocketChannel itsChannel;
public boolean getConnection(Selector selector, String host, int port)
{
try
{
itsSelector = selector;
itsChannel = SocketChannel.open();
itsChannel.configureBlocking(false);
itsChannel.register(itsSelector, SelectionKey.OP_CONNECT);
itsChannel.connect(new InetSocketAddress(host, port));
if (itsChannel.isConnectionPending())
{
while (!itsChannel.finishConnect())
{
// waiting until connection is finished
}
}
itsChannel.register(itsSelector, SelectionKey.OP_WRITE);
return (itsChannel != null);
}
catch (IOException ex)
{
close();
if(ex instanceof ConnectException)
{
LOGGER.log(Level.WARNING, "The remoteserver cannot be reached");
}
}
}
public void close()
{
try
{
if (itsChannel != null)
{
itsChannel.close();
itsChannel.socket().close();
itsSelector.selectNow();
}
}
catch (IOException e)
{
LOGGER.log(Level.WARNING, "Connection cannot be closed");
}
}
This program runs on Red Hat Enterprise Linux Server release 6.2 (Santiago)
When number of concurrent sockets are in establishment phase, file descriptor limit reaches a max value and I see below exception while trying to establish more socket connections.
java.net.SocketException: Too many open files
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:408)
This happens only when the remote Node is down, and while it is up, all is fine.
When the remote TCP server is down, below exception is thrown as is handled as IOException in the above code
java.net.ConnectException: Connection refused: no further information
at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
at sun.nio.ch.SocketChannelImpl.finishConnect(Unknown Source)
Is there any way to forcefully close the underlying file descriptor in this case.
Thanks in advance for all the help.
private Selector itsSelector;
I cannot see the point of this declaration. You can always get the selector the channel is registered with, if you need it, which you never do. Possibly you are leaking Selectors?
itsChannel.configureBlocking(false);
itsChannel.register(itsSelector, SelectionKey.OP_CONNECT);
Here you are registering for OP_CONNECT but never making the slightest use of the facility.
itsChannel.connect(new InetSocketAddress(host, port));
Here you are starting a pending connection.
if (itsChannel.isConnectionPending())
It is. You just started it. The test is pointless.
{
while (!itsChannel.finishConnect())
{
// waiting until connection is finished
}
}
This is just a complete waste of time and space. If you don't want to use the selector to detect when OP_CONNECT fires, you should call connect() before setting the channel to non-blocking, and get rid of this pointless test and loop.
itsChannel.register(itsSelector, SelectionKey.OP_WRITE);
return (itsChannel != null);
itsChannel cannot possibly be null at this point. The test is pointless. You would be better off allowing the IOExceptions that can arise to propagate out of this method, so that the caller can get some idea of the failure mode. That also places the onus on the caller to close on any exception, not just the ones you're catching here.
catch (IOException ex)
{
close();
if(ex instanceof ConnectException)
{
LOGGER.log(Level.WARNING, "The remoteserver cannot be reached");
}
}
See above. Remove all this. If you want to distinguish ConnectException from the other IOExceptions, catch it, separately. And you are forgetting to log anything that isn't a ConnectException.
public void close()
{
try
{
if (itsChannel != null)
{
itsChannel.close();
itsChannel.socket().close();
itsSelector.selectNow();
The second close() call is pointless, as the channel is already closed.
catch (IOException e)
{
LOGGER.log(Level.WARNING, "Connection cannot be closed");
}
I'm glad to see you finally logged an IOException, but you're not likely to get any here.
Don't write code like this.
Here's what I know so far (please correct me):
In the RabbitMQ Java client, operations on a channel throw IOException when there is a general network failure (malformed data from broker, authentication failures, missed heartbeats).
Operations on a channel can also throw the ShutdownSignalException unchecked exception, typically an AlreadyClosedException when we tried to perform an action on the channel/connection after it has been shut down.
The shutting down process happens in the event of "network failure, internal failure or explicit local shutdown" (e.g. via channel.close() or connection.close()). The shutdown event propagates down the "topology", from Connection -> Channel -> Consumer, and when the Channel it calls the Consumer's handleShutdown() method gets called.
A user can also add a shutdown listener which is called after the shutdown process completes.
Here is what I'm missing:
Since an IOException indicates a network failure, does it also initiate a shutdown request?
How does using auto-recovery mode affect shutdown requests? Does it cause channel operations to block while it tries to reconnect to the channel, or will the ShutdownSignalException still be thrown?
Here is how I'm handling exceptions at the moment, is this a sensible approach?
My setup is that I'm polling a QueueingConsumer and dispatching tasks to a worker pool. The rabbitmq client is encapsulated in MyRabbitMQWrapper here. When an exception occurs polling the queue I just gracefully shutdown everything and restart the client. When an exception occurs in the worker I also just log it and finish the worker.
My biggest worry (related to Question 1): Suppose an IOException occurs in the worker, then the task doesn't get acked. If the shutdown does not then occur, I now have an un-acked task that will be in limbo forever.
Pseudo-code:
class Main {
public static void main(String[] args) {
while(true) {
run();
//Easy way to restart the client, the connection has been
//closed so RabbitMQ will re-queue any un-acked tasks.
log.info("Shutdown occurred, restarting in 5 seconds");
Thread.sleep(5000);
}
}
public void run() {
MyRabbitMQWrapper rw = new MyRabbitMQWrapper("localhost");
try {
rw.connect();
while(!Thread.currentThread().isInterrupted()) {
try {
//Wait for a message on the QueueingConsumer
MyMessage t = rw.getNextMessage();
workerPool.submit(new MyTaskRunnable(rw, t));
} catch (InterruptedException | IOException | ShutdownSignalException e) {
//Handle all AMQP library exceptions by cleaning up and returning
log.warn("Shutting down", e);
workerPool.shutdown();
break;
}
}
} catch (IOException e) {
log.error("Could not connect to broker", e);
} finally {
try {
rw.close();
} catch(IOException e) {
log.info("Could not close connection");
}
}
}
}
class MyTaskRunnable implements Runnable {
....
public void run() {
doStuff();
try {
rw.ack(...);
} catch (IOException | ShutdownSignalException e) {
log.warn("Could not ack task");
}
}
}
I'm using java mail to connect with gmail and I'm keeping one store for the all actions. (Store is set to static.).
And the IMAPFolder instances are attached with imap listeners. So the folders are kept always open. (Folder close is not called any time) But while running after few minutes I'm getting FolderClosedException. After that exception, though the folder can be reopened but the idle() command cannot be issued again, which will result in NullPointerException.
Is there any wrong with keeping folders open always?
Thanks in advance.
===================================================================
[Edit]
Here I'm pasting the actual code i'm doing POC with. The NullPointerException comes when I check .isConnected() after reconnecting the store. Below is the run method of Thread which sends idle() command to the store.
public void run() {
while (true) {
try {
System.out.println("Checking connectivity...");
if (store.isConnected()) {
store.idle();
System.out.println("IDLE send...");
} else {
Thread.sleep(5000);
System.out.println("Tring to connect...");
//Trying to reconnect to the store.
store.connect();
System.out.println("Previous store connected again");
}
} catch (InterruptedException ex) {
System.out.println("InterruptedException...");
} catch (StoreClosedException ex) {
System.out.println("StoreClosedException...");
} catch (MessagingException ex) {
System.out.println("MessagingException...");
}
}
}
Here is the stack trace:
Exception in thread "Thread-1" java.lang.NullPointerException
at com.sun.mail.imap.IMAPStore.waitIfIdle(IMAPStore.java:1881)
at com.sun.mail.imap.IMAPStore.getStoreProtocol(IMAPStore.java:946)
at com.sun.mail.imap.IMAPStore.isConnected(IMAPStore.java:1347)
at pocworks.POCWorks1$IDLEThread.run(POCWorks1.java:125)
Generally, mail servers don't like you to keep connections open when you're not using them. Typical IMAP servers will give you 30 minutes before they time out an unused connection; Gmail may be more aggressive.
I'm using a variation of the example at http://svn.apache.org/repos/asf/activemq/trunk/assembly/src/release/example/src/StompExample.java to receive message from a queue. What I'm trying to do is to keep listening to a queue and perform some action upon reception of a new message. The problem is that I couldn't find a way to register a listener to any of the related objects. I've tried something like:
public static void main(String args[]) throws Exception {
StompConnection connection = null;
try {
connection = new StompConnection();
connection.open("localhost", 61613);
connection.connect("admin", "activemq");
connection.subscribe("/queue/worker", Subscribe.AckModeValues.AUTO);
while (true) {
StompFrame message = connection.receive();
System.out.println(message.getBody());
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
but this doesn't work as a time out occurs after a few seconds (java.net.SocketTimeoutException: Read timed out). Is there anything I can do to indefinitely listen to this queue?
ActiveMQ's StompConnection class is a relatively primitive STOMP client. Its not capable of async callbacks on Message or for indefinite waits. You can pass a timeout to receive but depending on whether you are using STOMP v1.1 it could still timeout early if a heart-beat isn't received in time. You can of course always catch the timeout exception and try again.
For STOMP via Java you're better off using StompJMS or the like which behaves like a real JMS client and allows for async Message receipt.
#Tim Bish: I tried StompJMS, but couldn't find any example that I could use (maybe you can provide a link). I 'fixed' the problem by setting the timeout to 0 which seems to be blocking.
even i was facing the same issue.. you can fix this by adding time out to your receive() method.
Declare a long type variable.
long waitTimeOut = 5000; //this is 5 seconds
now modify your receive function like below.
StompFrame message = connection.receive(waitTimeOut);
This will definitely work.
I have a class that acquires an ActiveMQ connection using ActiveMQConnectionFactory.createConnection().
It then creates and owns the session, the destination and the consumer (queue) listening on that destination.
I call receive() or receive(millis) on the consumer to get my messages off the queue. In certain scenarios I have to kill (interrupt) the thread in which the receive method is being called. I try to close the session and the connection right after that. Unfortunately I am constantly getting an exception when calling close and the associated "ActiveMQ Transport" threads (and related connections to the broker) are staying alive. The exception I get is
org.myorg.awsiface.communication.MessagingException: Failed to close JMS connection
at
org.myorg.aws.communication.transport.JMSMessageTransport.cleanUp(JMSMessageTransport.java:253)
at
org.myorg.aws.communication.protocol.ContextFinishedProtocol.cleanUp(ContextFinishedProtocol.java:94)
at org.myorg.myservice.job.Job.run(Job.java:206)
Caused by: javax.jms.JMSException: java.io.InterruptedIOExceptio)
at org.apache.activemq.util.JMSExceptionSupport.create(JMSExceptionSupport.java:62)
at org.apache.activemq.ActiveMQConnection.doAsyncSendPacket(ActiveMQConnection.java:1227)
at org.apache.activemq.ActiveMQConnection.asyncSendPacket(ActiveMQConnection.java:1219)
at org.apache.activemq.ActiveMQSession.asyncSendPacket(ActiveMQSession.java:1799)
at org.apache.activemq.ActiveMQMessageConsumer.doClose(ActiveMQMessageConsumer.java:636)
at org.apache.activemq.ActiveMQMessageConsumer.close(ActiveMQMessageConsumer.java:627)
at org.myorg.aws.communication.transport.JMSMessageTransport.cleanUp(JMSMessageTransport.java:232)
... 2 more
Caused by: java.io.InterruptedIOException
at org.apache.activemq.transport.WireFormatNegotiator.oneway(WireFormatNegotiator.java:102)
at org.apache.activemq.transport.MutexTransport.oneway(MutexTransport.java:40)
at org.apache.activemq.transport.ResponseCorrelator.oneway(ResponseCorrelator.java:60)
at org.apache.activemq.ActiveMQConnection.doAsyncSendPacket(ActiveMQConnection.java:1225)
... 7 more
I've tried the following connection URLs
failover://tcp://broker.ip.address:61616
tcp://broker.ip.address:61616
failover://tcp://broker.ip.address:61616?trace=true&closeAsync=false
Also I've tried using the MessageConsumer::receiveNoWait() call and just executing my own Thread.sleep, but I always end up with the exception above whenever I call the following to close the connection
try {
// I added the following two lines to see if the taskRunner was handling the threads - still no luck
TaskRunnerFactory taskRunner = ((ActiveMQConnection)connection).getSessionTaskRunner();
taskRunner.shutdown();
if (producer != null) {
producer.close();
}
if (consumer != null) {
consumer.close();
}
session.close();
if (connection instanceof ActiveMQConnection) {
ActiveMQConnection amqConnection = (ActiveMQConnection) connection;
amqConnection.stop();
}
connection.stop();
connection.close();
}
catch (ConnectionClosedException e) {
// NOOP - this is ok
}
catch (Exception e) {
throw new MessagingException("Failed to close JMS connection", e, log);
}
I'm not sure why the close is not working for you. But you can accomplish what you want by using an asynchronous message listener.
Connection connection = connectionFactory.createConnection();
connection.start();
Session session =
connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination queue = session.createQueue("queueName");
Consumer consumer = session.createConsumer( queue );
consumer.setMessageListener( new MessageListener()
{
public void onMessage( Message message )
{
// whatever was after the receive() method call
}
} );
Then there's no need to be interrupted. When you are done, close things out:
consumer.close();
session.close();
queue.close();
connection.close();
One solution could be to set daemon flag on TCP ActiveMQ transport thread,
e.g. tcp://URI:PORT?daemon=true
Check out ActiveMQ documentation: http://activemq.apache.org/tcp-transport-reference.html