Как узнать, когда потеряно соединение с темой JMS?
У меня есть клиентское приложение с расширенными возможностями Java, которое при запуске регистрирует долговременную подписку в удаленной теме JMS HornetQ. Однако, если сервер перезагружается, соединение теряется и может быть восстановлено только путем перезапуска клиентского приложения. Это приводит к запутанным ситуациям, когда сообщения JMS не принимаются и после перезапуска клиента сразу принимается много сообщений.
Простым решением для восстановления соединения было бы запустить таймер, чтобы периодически проверять, является ли соединение все еще действующим, и пытаться восстановить соединение в противном случае. В качестве альтернативы сервер может отправить контрольное сообщение клиенту и попытаться восстановить соединение, если контрольное сообщение не получено по истечении определенного периода (как упомянуто в этом ответе).
Но оба кажутся неуклюжими подходами к этой проблеме, и поэтому я хотел бы знать, есть ли лучшее решение, чтобы узнать, что соединение больше не доступно?
1 ответ
Чтобы получить уведомление об отключении, необходимо зарегистрировать ExceptionListener
на ваше TopicConnection
прежде чем начать соединение.
private void subscribe() throws JMSException {
// get context / create connection and session / etc.
TopicConnection connection = ...
connection.setExceptionListener(this::handleExceptions);
connection.start();
}
в ExceptionListener
Вы можете проверить код ошибки полученного JMSException
, (Коды ошибок зависят от поставщика)
В случае HornetQ код ошибки DISCONNECT
Получено после потери соединения.
private static final String HORNETQ_DISCONNECT_ERROR_CODE = "DISCONNECT";
private void handleExceptions(final JMSException jmsException) {
final String errorCode = jmsException.getErrorCode();
if (HORNETQ_DISCONNECT_ERROR_CODE.equals(errorCode)) {
tryConnect();
}
}
Затем вы можете запустить таймер с автоматической отменой, который пытается восстановить соединение каждые x секунд, пока не выполнится успешно.
private static final long SUBSCRIBE_RETRY_TIME_OUT_IN_MILLIS = 60000;
private void tryConnect() {
final Timer timer = new Timer("JMS-Topic-Reconnection-Timer", true);
final TimerTask timerTask = new TimerTask() {
@Override
public void run() {
try {
subscribe();
// cancel the timer, after the subscription succeeds
timer.cancel();
}
catch (final Exception e) {
logger.info("reconnect to jms topic failed: {}", e.getMessage());
}
}
};
timer.schedule(timerTask, SUBSCRIBE_RETRY_TIME_OUT_IN_MILLIS, SUBSCRIBE_RETRY_TIME_OUT_IN_MILLIS);
}