Обработка исключений / ошибок Camel на маршруте транзакции, не вызывающем исключения клиента

Я работаю с системой, управляемой командными событиями, с использованием JMS и Apache Camel для маршрутизации. В следующей ситуации:

  • Я отправляю системе команду запрос-ответ "X".

  • Система получает «X» по проверенному верблюжьему маршруту.

  • Во время обработки «X» система отправляет несколько событий «Y» и «Z», но как часть маршрута транзакции они не должны сбрасываться до тех пор, пока транзакция не будет завершена.

  • Возникает исключение времени выполнения, которое должно вызвать откат транзакции.

Я хочу иметь возможность перехватывать исключение и отвечать клиенту подлинным сообщением (а не исключением). Таким образом, я начал реализовывать обработчик ошибок:

    onException(RuntimeException.class)
        .handled(true)
        .markRollbackOnly()
        .filter(header(Header.REPLY_TO.getName()).isNotNull())
        .to(DESTINATION_FOR_EXCEPTION_HANDLING)
        .to(DESTINATION_FOR_REPLIES);

Где:

  • DESTINATION_FOR_EXCEPTION_HANDLING - это bean-компонент, который принимает исключение и возвращает объект сообщения
  • DESTINATION_FOR_REPLIES - это bean-компонент, который устанавливает тело вывода для объекта сообщения.

У меня проблема в том, что если я включу «markRollbackOnly ()», это:

  • Предотвращает смывание "Y" и "Z" - ХОРОШО
  • Вызывает исключение обмена на клиенте, выполняющем запрос Ответ - ПЛОХО

И если я его не включаю, то:

  • "Y" и "Z" покраснели - ПЛОХО
  • Я получаю подлинный объект сообщения на клиенте - ХОРОШО

Как я могу настроить верблюда, чтобы предотвратить сброс сообщений в транзакции и при этом иметь возможность преобразовать исключение в обработанное сообщение об ошибке?


person James    schedule 03.03.2015    source источник


Ответы (2)


Если при отправке onException в эти 2 пункта назначения используется тот же компонент Camel, что и в from, вам потребуется использовать для этого отдельный компонент, чтобы они были независимыми. Поскольку в противном случае откат заставил бы их всех откатиться.

Предполагая, что вы используете ActiveMQ, вы просто объявляете два компонента

   <bean id="activemq" ...>

   <bean id="activemq2" ...>

А затем используйте activemq2 в onException. Затем можно настроить использование того же brokerUrl и всего такого. А для 2-го вам может потребоваться установить для него значение transact = false.

person Claus Ibsen    schedule 03.03.2015
comment
Разве это не вызовет исключение на клиенте, поскольку исходный компонент по-прежнему будет отвечать с исключением обмена? - person James; 03.03.2015

Я попробовал подход Клауса, но по какой-то причине не смог заставить его работать, должно быть, я неправильно понял или настроил что-то неправильно.

В конце концов я решил эту проблему, распространив вторую транзакцию внутри себя, один из обработчиков ошибок, я мог затем «markRollbackOnlyLast» вторую транзакцию, но ответить «хорошим» сообщением о первичной транзакции:

    TransactionTemplate newTransactionTemplate = new TransactionTemplate(platformTransactionManager);
    newTransactionTemplate.setPropagationBehavior(PROPAGATION_REQUIRES_NEW);
    Policy requireNewTransaction = new SpringTransactionPolicy(newTransactionTemplate);

    onException(RuntimeException.class)
        .onWhen(header(Header.REPLY_TO.getName()).isNotNull())
            .log(LoggingLevel.ERROR, EXCEPTION_STACKTRACE)
            .to(PROCESSOR_FOR_EXCEPTION_HANDLING)
            .to(PROCESSOR_FOR_REPLY)
            .handled(true)
            .markRollbackOnlyLast();

    from(FROM)
        .policy(requireNewTransaction)...
person James    schedule 09.03.2015