Мне интересно узнать, как другие люди справляются с восстановлением из-за неправильного соединения, используя официальную клиентскую библиотеку RabbitMQ java. Мы используем его для подключения наших серверов приложений к нашему кластеру RabbitMQ, и мы реализовали несколько различных способов восстановления после сбоя соединения, но не все они чувствуют себя совершенно правильно.
Представьте себе это псевдо-приложение:
public class OurClassThatStartsConsumers {
Connection conn;
public void start() {
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername("someusername");
factory.setPassword("somepassword");
factory.setHost("somehost");
conn = factory.newConnection();
new Thread(new Consumer(conn.createChannel())).start();
}
}
class Consumer1 implements Runnable {
public Consumer1(Channel channel) {
this.channel = channel;
}
@Override
public void run() {
while (true) {
... consume incoming messages on the channel...
// How do we handle that the connection dies?
}
}
}
В реальном мире у нас есть несколько сотен потребителей. Итак, что происходит, если соединение умирает? В приведенном выше примере Consumer1 не может восстановиться, когда соединение закрывается, канал также закрывается, состояние, из которого мы не можем восстановить. Поэтому давайте рассмотрим некоторые способы решения этой проблемы:
Решение A)
Пусть каждый потребитель имеет свое собственное соединение и регистрирует события, которые запускаются, когда соединение умирает, а затем обрабатывает повторное подключение.
Плюсы: он работает
Минусы:
- Поскольку у нас много потребителей, мы, вероятно, не хотим, чтобы многие соединения.
- Возможно, у нас есть много дублированного кода для повторное подключение к кролику и переподключение рекордера
Решение B)
Попросите каждого потребителя использовать одно и то же соединение и подписаться на него.
Плюсы: меньше соединений, чем в решении A
Минусы: поскольку соединение закрыто, нам нужно его снова открыть/заменить. Клиентская библиотека java, похоже, не дает возможности повторно открыть соединение, поэтому нам придется заменить его новым подключением, а затем как-то уведомить всех потребителей об этом новом подключении, и им придется воссоздавать каналы и потребителей, Опять же, много логики, которую я не хочу видеть у потребителя, заканчивается там.
Решение C)
Wrap Connection
и Channel
классы - это классы, которые обрабатывают логику повторного подключения, потребитель должен знать только о классе WrappedChannel
. При сбое соединения WrappedConnection
будет иметь дело с восстановлением соединения и после подключения WrappedConnection
автоматически создаст новые каналы и зарегистрирует потребителей.
Плюсы: он работает - это на самом деле решение, которое мы используем сегодня.
Минусы: Это похоже на хак, я думаю, что это то, что должно быть более элегантно обработано основной библиотекой.
Может быть, есть намного лучший способ? Документация API не так много говорит о восстановлении от неисправного соединения. Любой вход оценивается:)