Hi Gary,
Thanks for your quick reply.
As you suggested I have tested sub classing the DMLC and overriding both the sleepInbetweenRecoveryAttempts() (to calculate the sleep time) and the refreshConnectionUntilSuccessful() methods to keep track of the retry attempts.
This appears to be working well as per the log output below:
Code:
2012-11-02 10:33:49,186 [testListener-1] WARN com.anz.otc.jms.ExpBackoffMessageListenerContainer - Could not refresh JMS Connection for destination 'DOTC.OUTBOUND.TRADE.FEED' - retrying in 10000 ms. Cause: Could not connect to broker URL: tcp://localhost:61616. Reason: java.net.ConnectException: Connection refused: connect
2012-11-02 10:34:00,154 [testListener-1] WARN com.anz.otc.jms.NamedMessageListenerContainer - Could not refresh JMS Connection for destination 'DOTC.OUTBOUND.TRADE.FEED' - retrying in 20000 ms. Cause: Could not connect to broker URL: tcp://localhost:61616. Reason: java.net.ConnectException: Connection refused: connect
2012-11-02 10:34:21,280 [testListener-1] WARN com.anz.otc.jms.ExpBackoffMessageListenerContainer- Could not refresh JMS Connection for destination 'DOTC.OUTBOUND.TRADE.FEED' - retrying in 40000 ms. Cause: Could not connect to broker URL: tcp://localhost:61616. Reason: java.net.ConnectException: Connection refused: connect
Do you see any issues with this approach?
Code:
/**
* Extension of Springs DefaultMessageListener to support an "Exponential back off Algorithm" when
* performing connection recovery.
*/
public class ExponentialBackoffListenerContainer extends DefaultMessageListenerContainer {
private long recoveryInterval;
private int recoveryAttempts = 0;
private int maximumRecoveryIntervalInSeconds;
@Override
public String toString() {
return getBeanName();
}
@Override
protected void refreshConnectionUntilSuccessful() {
while (isRunning()) {
try {
if (sharedConnectionEnabled()) {
refreshSharedConnection();
}
else {
final Connection con = createConnection();
JmsUtils.closeConnection(con);
}
logger.info("Successfully refreshed JMS Connection");
recoveryAttempts = 0;
break;
}
catch (final Exception ex) {
recoveryAttempts++;
final StringBuilder msg = new StringBuilder();
msg.append("Could not refresh JMS Connection for destination '");
msg.append(getDestinationDescription()).append("' - retrying in ");
msg.append(calculateRetryDelay()).append(" ms. Cause: ");
msg.append(ex instanceof JMSException ? JmsUtils.buildExceptionMessage((JMSException) ex) : ex
.getMessage());
if (logger.isDebugEnabled()) {
logger.warn(msg, ex);
}
else {
logger.warn(msg);
}
}
sleepInbetweenRecoveryAttempts();
}
}
@Override
protected void sleepInbetweenRecoveryAttempts() {
if (this.recoveryInterval > 0) {
try {
Thread.sleep(calculateRetryDelay());
}
catch (InterruptedException interEx) {
// Re-interrupt current thread, to allow other threads to react.
Thread.currentThread().interrupt();
}
}
}
private long calculateRetryDelay() {
if (recoveryAttempts == 0) {
return recoveryInterval;
}
else {
return Math.min(Math.round(recoveryInterval * Math.pow(2, recoveryAttempts)),
(maximumRecoveryIntervalInSeconds * 1000));
}
}
public void setMaximumRecoveryIntervalInSeconds(int maximumRecoveryIntervalInSeconds) {
this.maximumRecoveryIntervalInSeconds = maximumRecoveryIntervalInSeconds;
}
@Override
public void setRecoveryInterval(long recoveryInterval) {
super.setRecoveryInterval(recoveryInterval);
this.recoveryInterval = recoveryInterval;
}
}
Now as we are using Apache Camel in our application I need to figure out if it is possible to wire a custom MessageListenerContainer bean into the JMSComponent.
Thanks,
Patrick Bray