Я перехожу с ActiveMQ Classic на ActiveMQ Artemis, и мне нужно вручную обрабатывать аварийное переключение клиента между двумя независимыми серверами. Протокол аварийного переключения: из ActiveMQ Classic недоступен в Artemis. Как я могу реализовать аварийное переключение на уровне приложения с помощью ExceptionListener, чтобы добиться автоматического повторного подключения клиента, как это происходило в ActiveMQ Classic? У нас есть ограничение: оба брокера работают как встроенные в приложение, так и независимо. Невозможно определить кластер или основной и резервный брокер, как описано здесь.
Полный контекст:
Я нахожусь в процессе миграции от ActiveMQ Classic до ActiveMQ Artemis. Наша установка состоит из двух автономных приложений Spring Boot, каждое из которых имеет встроенный брокер Artemis, работающий независимо на сервере1 и сервере2.
Конфигурация классического клиента ActiveMQ:
В ActiveMQ Classic мы использовали протокол аварийного переключения: для автоматической обработки повторных подключений клиентов при выходе из строя одного или обоих серверов. URL-адрес брокера был настроен следующим образом:
[code]import org.apache.activemq.ActiveMQConnectionFactory;
@Bean
public ConnectionFactory connectionFactory(String user, String credential) {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("failover:(tcp://server1:port1,tcp://server2:port2)?jms.useAsyncSend=true&initialReconnectDelay=100&timeout=2000&randomize=false");
factory.setTrustAllPackages(true);
factory.setUserName(user);
factory.setPassword(credential);
return factory;
}
[/code]
Конфигурация клиента ActiveMQ Artemis:
В Artemis мы обновили URL-адрес брокера, но обнаружили, что протокол аварийного переключения: больше недоступен. Наш текущий URL-адрес выглядит следующим образом:
Код: Выделить всё
import org.apache.activemq.artemis.jms.client.ActiveMQJMSConnectionFactory;
public ConnectionFactory connectionFactory(String user, String credential) {
ActiveMQJMSConnectionFactory factory = new ActiveMQJMSConnectionFactory("(tcp://server1:port1,tcp://server2:port2)?jms.useAsyncSend=true&initialReconnectDelay=100&timeout=2000&sslEnabled=false&failoverAttempts=-1&useTopologyForLoadBalancing=false&connectionLoadBalancingPolicyClassName=org.apache.activemq.artemis.api.core.client.loadbalance.FirstElementConnectionLoadBalancingPolicy", user, credential);
return factory;
}
Проблема.
Мы стремимся реализовать аварийное переключение на уровне приложения вручную, как описано здесь. Наша цель — перехватить события отключения и попытаться выполнить повторное подключение программным способом.Проблема 1: первоначальное переключение соединения
Когда сервер1 не работает, клиент не пытается автоматически подключиться к серверу2, и выдается следующее исключение:
Код: Выделить всё
org.springframework.jms.UncategorizedJmsException: Uncategorized exception occurred during JMS processing; nested exception is ActiveMQNotConnectedException[errorType=NOT_CONNECTED message=AMQ219007: Cannot connect to server(s). Tried with all available servers.]
Когда клиент подключается к серверу1, а сервер1 отключается, соединение потеряно, и клиент не пытается повторно подключиться к серверу2. Прослушиватель исключений вызывается только после server1 резервного копирования.
Код: Выделить всё
2024-07-29 10:12:45,318 [Thread-0 (ActiveMQ-client-global-threads)] INFO o.a.a.a.c.client [] - AMQ214036: Connection closure to server1/server1:port1 has been detected: AMQ219015: The connection was disconnected because of server shutdown [code=DISCONNECTED]
2024-07-29 10:13:09,546 [Thread-6] INFO d.d.m.j.ExampleListener [] - received exception in topic listener: {}
jakarta.jms.JMSException: ActiveMQDisconnectedException[errorType=DISCONNECTED message=AMQ219015: The connection was disconnected because of server shutdown]
2024-07-29 11:32:29,339 [Thread-6] INFO d.d.m.j.ExampleListener [] - received exception in topic listener: {}
jakarta.jms.JMSException: ActiveMQDisconnectedException[errorType=DISCONNECTED message=AMQ219015: The connection was disconnected because of server shutdown]
at org.apache.activemq.artemis.jms.client.ActiveMQConnection$JMSFailureListener.connectionFailed(ActiveMQConnection.java:724) ~[artemis-jakarta-client-2.33.0.jar:2.33.0]
at org.apache.activemq.artemis.jms.client.ActiveMQConnection$JMSFailureListener.connectionFailed(ActiveMQConnection.java:745) ~[artemis-jakarta-client-2.33.0.jar:2.33.0]
at org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryImpl.callSessionFailureListeners(ClientSessionFactoryImpl.java:878) ~[artemis-core-client-2.33.0.jar:2.33.0]
at org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryImpl.callSessionFailureListeners(ClientSessionFactoryImpl.java:866) ~[artemis-core-client-2.33.0.jar:2.33.0]
at org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryImpl.failoverOrReconnect(ClientSessionFactoryImpl.java:812) ~[artemis-core-client-2.33.0.jar:2.33.0]
at org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryImpl.handleConnectionFailure(ClientSessionFactoryImpl.java:576) ~[artemis-core-client-2.33.0.jar:2.33.0]
at org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryImpl$DelegatingFailureListener.connectionFailed(ClientSessionFactoryImpl.java:1417) ~[artemis-core-client-2.33.0.jar:2.33.0]
at org.apache.activemq.artemis.spi.core.protocol.AbstractRemotingConnection.callFailureListeners(AbstractRemotingConnection.java:98) ~[artemis-core-client-2.33.0.jar:2.33.0]
at org.apache.activemq.artemis.core.protocol.core.impl.RemotingConnectionImpl.fail(RemotingConnectionImpl.java:209) ~[artemis-core-client-2.33.0.jar:2.33.0]
at org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryImpl$CloseRunnable.run(ClientSessionFactoryImpl.java:1182) ~[artemis-core-client-2.33.0.jar:2.33.0]
at org.apache.activemq.artemis.utils.actors.OrderedExecutor.doTask(OrderedExecutor.java:57) ~[artemis-commons-2.33.0.jar:2.33.0]
at org.apache.activemq.artemis.utils.actors.OrderedExecutor.doTask(OrderedExecutor.java:32) ~[artemis-commons-2.33.0.jar:2.33.0]
at org.apache.activemq.artemis.utils.actors.ProcessorBase.executePendingTasks(ProcessorBase.java:68) ~[artemis-commons-2.33.0.jar:2.33.0]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[?:?]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[?:?]
at org.apache.activemq.artemis.utils.ActiveMQThreadFactory$1.run(ActiveMQThreadFactory.java:118) ~[artemis-commons-2.33.0.jar:2.33.0]
Caused by: org.apache.activemq.artemis.api.core.ActiveMQDisconnectedException: AMQ219015: The connection was disconnected because of server shutdown
... 7 more
2024-07-29 11:32:29,351 [Thread-6] WARN d.d.m.j.ExampleListener [] - Exception is not an instance of ActiveMQDisconnectedException
Код: Выделить всё
public class ExampleListener implements ExceptionListener {
private static final Logger LOG = LoggerFactory.getLogger(ExampleListener.class);
@Override
public void onException(final JMSException exception) {
LOG.info("Received exception in topic listener: {}", exception);
if (exception.getLinkedException() instanceof ActiveMQDisconnectedException) {
// This if-Statement is always false.
ActiveMQDisconnectedException e = (ActiveMQDisconnectedException) exception.getLinkedException();
LOG.info("Disconnected exception type: {}", e.getType());
LOG.info("Disconnected message type: {}", e.getMessage());
// Handle reconnection logic here
} else {
LOG.warn("Exception is not an instance of ActiveMQDisconnectedException");
}
}
}
Вопросы:
- Как мы можем обрабатывать повторное подключение, если прослушиватель исключений вызывается только после > сервер перезапущен?
Как мы можем программно определить, какой сервер не работает, и попытаться повторно подключиться к другому серверу, аналогично поведению при отказе: в ActiveMQ Classic? li>
Подробнее здесь: https://stackoverflow.com/questions/788 ... hout-built