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 е компонент, който приема изключението и връща обект на съобщение
  • DESTINATION_FOR_REPLIES е компонент, който задава изходящото тяло към обекта на съобщението

Проблемът, който имам, е, че ако включа "markRollbackOnly()", той:

  • Предотвратява промиването на "Y" и "Z" - ДОБРЕ
  • Предизвиква изключение за обмен на клиента, който прави requestReply - BAD

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

  • "Y" & "Z" се зачервяват - ЛОШО
  • Получавам обекта на истинското съобщение на клиента - ДОБРЕ

Как мога да конфигурирам camel така, че да предотвратява изтриването на съобщения в транзакцията и все пак да мога да конвертирам изключението в обработено съобщение за грешка?


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


Отговори (2)


Ако изпращането на onException до тези 2 дестинации използва същия Camel компонент като from, тогава ще трябва да използвате отделен компонент за това, така че те да са независими. Тъй като в противен случай връщането назад би накарало всички тях да се върнат назад.

Ако приемем, че използвате ActiveMQ, вие просто декларирате два компонента

   <bean id="activemq" ...>

   <bean id="activemq2" ...>

И след това използвайте activemq2 в onException. След това може да бъде конфигуриран да използва същия brokerUrl и всичко това. А за второто може да се наложи да го настроите на transacted=false.

person Claus Ibsen    schedule 03.03.2015
comment
Това няма ли да доведе до изключение на клиента, тъй като оригиналният компонент все още ще отговори с изключение за обмен? - person James; 03.03.2015

Опитах подхода на Клаус, но не можах да го накарам да работи по някаква причина, трябва да съм разбрал погрешно или да съм настроил нещо неправилно.

В крайна сметка реших това, като разпространих втора транзакция вътрешно, един от манипулаторите на грешки, след което можех да „маркирамRollbackOnlyLast“ втората транзакция, но да отговоря с „добро“ съобщение за основната транзакция:

    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