Java JMS - прослушиватель сообщений и onException - PullRequest
0 голосов
/ 22 февраля 2020

У меня есть приложение с основным потоком и потоком JMS, которые общаются друг с другом через ActiveMQ 5.15.11. Я могу отправлять сообщения просто отлично, однако я хотел бы, чтобы был способ вернуть статус или ошибки. Я заметил, что MessageListener позволяет onSuccess() и onException(ex) как два события для прослушивания, однако я обнаружил, что вызывается только onSuccess().

Вот фрагменты моего кода.

JMS Тема:

ConnectionFactory factory = super.getConnectionFactory();
Connection connection = factory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue(super.getQueue());
MessageConsumer consumer = session.createConsumer(queue);
consumer.setMessageListener(m -> {
   try {
      super.processRmbnConfigMsg(m);
   } catch (JMSException | IOException e) {
      LOG.error(e.getMessage(), e);

      // I can only use RuntimeException. 
      // Also this exception is what I am expecting to get passed to the onException(..)
      // call in the main thread.
      throw new RuntimeException(e);
   }
});
connection.start();

Основная тема (отправка сообщений в JMS):

sendMessage(xml, new AsyncCallback() {
    @Override
    public void onException(JMSException e) {
        // I am expecting this to be that RuntimeException from the JMS thread.
        LOG.error("Error", e);
        doSomethingWithException(e);
    }

    @Override
    public void onSuccess() {
        LOG.info("Success");
    }
});

Я ожидаю, что исключения, сгенерированные в new RuntimeException(e), будут каким-то образом обнаружены в приемнике событий onException(JMSException e), даже если RuntimeException обернут.

Вместо этого я всегда получаю onSuccess() событий. Я предполагаю, что событие onException(..) происходит во время проблем со связью, но я хотел бы отправить обратно исключение вызывающей стороне.

Как мне выполнить sh задачу сбора ошибок в потоке JMS и отправки их обратно в мой вызывающий поток?

1 Ответ

3 голосов
/ 22 февраля 2020

Ваше ожидание основано на фундаментальном неправильном понимании JMS.

Одним из основных принципов обмена сообщениями через брокерские сети является то, что производители и потребители логически не связаны друг с другом. Другими словами ... Производитель отправляет сообщение брокеру, и ему не обязательно заботиться, успешно ли он потреблен или нет, и он, конечно, не будет знать, , кто потребляет его, или не имеет никакой гарантии, когда это будет израсходовано. Кроме того, потребитель не обязательно знает, когда и почему сообщение было отправлено или кто его отправил. Это обеспечивает большую гибкость между производителями и потребителями. JMS придерживается этого принципа enet от несвязанных производителей и потребителей.

Не существует прямого способа для потребителя сообщить производителю о проблеме с использованием отправленного им сообщения. Тем не менее, вы можете использовать так называемый «шаблон запроса / ответа», чтобы потребитель мог предоставить какую-то обратную связь производителю. Вы можете найти объяснение этого шаблона вместе с примером кода здесь .

Кроме того, используемый вами класс AsyncCallback не является частью JMS. Я полагаю, что org.apache.activemq.AsyncCallback предоставляется исключительно самим ActiveMQ, и он обеспечивает только обратные вызовы для успеха или неудачи для фактической операции send (т.е. не для потребления сообщения).

Наконец, вы должны знать, что бросание RuntimeException из onMessage метода javax.jms.MessageListener считается "ошибкой программирования" по спецификации JMS и его следует избегать. Раздел 8.7 спецификации JMS 2 гласит:

Слушатель может выбросить RuntimeException; однако это считается ошибкой программирования клиента. Слушатели с хорошим поведением должны отлавливать такие исключения и пытаться переадресовывать сообщения, вызывающие их, в какую-то форму, указанную в приложении c «необработанное сообщение». Результат выдачи RuntimeException слушателем зависит от режима подтверждения сеанса.

  • AUTO_ACKNOWLEDGE или DUPS_OK_ACKNOWLEDGE - сообщение будет немедленно доставлено. Количество раз, когда провайдер JMS будет повторно доставлять одно и то же сообщение, прежде чем отказаться, зависит от провайдера. Будет установлено поле заголовка сообщения JMSRedelivered, и свойство сообщения JMSXDeliveryCount будет увеличено для сообщения, доставляемого при этих обстоятельствах.

  • CLIENT_ACKNOWLEDGE - доставляется следующее сообщение для прослушивателя. Если клиент желает, чтобы предыдущее неподтвержденное сообщение было доставлено, он должен вручную восстановить сеанс.

  • Транзакционный сеанс - доставляется следующее сообщение для слушателя. Клиент может зафиксировать или откатить сеанс (другими словами, RuntimeException не выполняет автоматический откат сеанса).

...