Компонент Apache Camel JMS: bridgeErrorHandler не работает как описано - PullRequest
0 голосов
/ 16 октября 2019

Вопрос

Привет, я пытаюсь переместить обработку ошибок от потребителя JMS к обработчику ошибок моего верблюжьего маршрута, который представляет собой DLC, с использованием флага bridgeErrorHandler=true, ноJMSException, который возникает, когда я принимаю сообщение, никогда не обрабатывается DLC ErrorHandler, а вместо этого DefaultSpringErrorHandler и, таким образом, только регистрируется и игнорируется.

В моем DLC я настроил, что дополнительные шаги должныслучается, когда возникает исключение, которое теперь печально игнорируется. Может быть, вы можете сказать мне, что я сделал не так?

Вот подробности:

Настройка проекта

Я использую:

  • spring-boot: 2.1.0.RELEASE
  • apache camel: 2.23.3
  • camel-jms-starter: 2.23.3

Theмаршрут:

@Component
public class BridgeErrorHandlerTestQuellRoute extends RouteBuilder{

    private static final String ROUTE_ALIAS = "BridgeErrorHandlerTestQuellRoute";

    public static final String ENDPOINT_QUELLE = "{{BridgeErrorHandlerTestQuelle}}";

    @Override
    public void configure() {
        errorHandler(deadLetterChannel(DLCRoute.ENDPOINT_DLC));

        // @formatter:off
        from(ENDPOINT_QUELLE).routeId(ROUTE_ALIAS)
            .removeHeaders("*", "JMS*") // Entfernt alle nicht notwendigen JMS-Header
            .log(INFO, log, "Start Route: ${routeId}")
            .to("mock:mymock")
            .log(INFO, log, "Ende Route: ${routeId}")
        // @formatter:on
    }
}

конфигурация:

Сама конечная точка определяется в application.properties (хотя мне пришлось изменить название темы):

topic.props=subscriptionShared=true&\
            transacted=true&\
            recoveryInterval=-1&\
            connectionFactory=#connectionFactory&\
            bridgeErrorHandler=true

BridgeErrorHandlerTestQuelle=jms:topic:IBMMQSERVER/AT/ALL/MYTOPIC?durableSubscriptionName=BridgeErrorHandlerTest.bridgeerrorhandlertest&${topic.props}

bean фабрика соединений

фабрика соединений для IBM MQ:

    @Bean
    public ConnectionFactory connectionFactory() {
        try {
            MQConnectionFactory factory = new MQConnectionFactory();
            factory.setHostName(properties.getHost());
            factory.setPort(properties.getPort());
            factory.setQueueManager(properties.getQueueManager());
            factory.setChannel(properties.getChannel());
            factory.setStringProperty(WMQConstants.USERID, properties.getUser());
            factory.setStringProperty(WMQConstants.PASSWORD, properties.getPassword());
            factory.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
            return factory;
        } catch (JMSException e) {
            throw new RuntimeException(e);
        }
    }

исключение

Исключение возникает в: com.ibm.msg.client.wmq.common.internal.WMQUtils#computeTextFromBytes(byte[], int, int, com.ibm.mq.jmqi.system.JmqiCodepage) и является DetailedJMSException

WARN  EndpointMessageListener        : Execution of JMS message listener failed. Caused by: [org.apache.camel.RuntimeCamelException - Failed to extract body due to: com.ibm.msg.client.jms.DetailedJMSException: JMSCMQ1049: Mit dem Zeichensatz '1208(UTF-8) Unmappable Action: REPORT Unmappable Replacement: 63' kann die Zeichenfolge '[B@22b4f934' gar nicht oder nur teilweise konvertiert werden.
Es wurde versucht, Zeichenfolgedaten mit einem Zeichensatz zu versenden bzw. zu empfangen, der den Inhalt der Zeichenfolge nicht umsetzen kann.
Codieren Sie eine Nachricht nur mit einem Zeichensatz, von dem bekannt ist, dass er für die zu übertragenden Zeichenfolgedaten geeignet ist.. Message: 
[removed due to sensitive details]
org.apache.camel.RuntimeCamelException: Failed to extract body due to: com.ibm.msg.client.jms.DetailedJMSException: JMSCMQ1049: Mit dem Zeichensatz '1208(UTF-8) Unmappable Action: REPORT Unmappable Replacement: 63' kann die Zeichenfolge '[B@22b4f934' gar nicht oder nur teilweise konvertiert werden.
Es wurde versucht, Zeichenfolgedaten mit einem Zeichensatz zu versenden bzw. zu empfangen, der den Inhalt der Zeichenfolge nicht umsetzen kann.
Codieren Sie eine Nachricht nur mit einem Zeichensatz, von dem bekannt ist, dass er für die zu übertragenden Zeichenfolgedaten geeignet ist.. Message: 
  [removed due to sensitive details]
    at org.apache.camel.component.jms.JmsBinding.extractBodyFromJms(JmsBinding.java:176)
    at org.apache.camel.component.jms.JmsMessage.createBody(JmsMessage.java:227)
    at org.apache.camel.impl.MessageSupport.getBody(MessageSupport.java:54)
    at org.apache.camel.component.bean.AbstractBeanProcessor.process(AbstractBeanProcessor.java:132)
    at org.apache.camel.component.bean.BeanProcessor.process(BeanProcessor.java:53)
    at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:548)
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:138)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:101)
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201)
    at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:97)
    at org.apache.camel.component.jms.EndpointMessageListener.onMessage(EndpointMessageListener.java:113)
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:736)
    at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:696)
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:674)
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:318)
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:245)
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1189)
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1179)
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1076)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: com.ibm.msg.client.jms.DetailedJMSException: JMSCMQ1049: Mit dem Zeichensatz '1208(UTF-8) Unmappable Action: REPORT Unmappable Replacement: 63' kann die Zeichenfolge '[B@22b4f934' gar nicht oder nur teilweise konvertiert werden.
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at com.ibm.msg.client.commonservices.j2se.NLSServices.createException(NLSServices.java:319)
    at com.ibm.msg.client.commonservices.nls.NLSServices.createException(NLSServices.java:226)
    at com.ibm.msg.client.wmq.common.internal.WMQUtils.computeTextFromBytes(WMQUtils.java:382)
    at com.ibm.msg.client.wmq.common.internal.WMQUtils.computeTextFromByteBuffer(WMQUtils.java:421)
    at com.ibm.msg.client.wmq.common.internal.messages.WMQTextMessage.getText(WMQTextMessage.java:240)
    at com.ibm.msg.client.jms.internal.JmsTextMessageImpl.getText(JmsTextMessageImpl.java:205)
    at com.ibm.jms.JMSTextMessage.getText(JMSTextMessage.java:124)
    at org.apache.camel.component.jms.JmsBinding.extractBodyFromJms(JmsBinding.java:161)
    ... 22 common frames omitted
Caused by: java.nio.charset.MalformedInputException: Input length = 1
    at java.nio.charset.CoderResult.throwException(CoderResult.java:281)
    at java.nio.charset.CharsetDecoder.decode(CharsetDecoder.java:816)
    at com.ibm.mq.jmqi.system.JmqiCodepage.bytesToString(JmqiCodepage.java:745)
    at com.ibm.msg.client.wmq.common.internal.WMQUtils.computeTextFromBytes(WMQUtils.java:375)
    ... 27 common frames omitted

Ответы [ 2 ]

1 голос
/ 18 октября 2019

Хорошо, мы улучшаем это для Camel 3, где вы можете включить eagerLoadingOfProperties (на уровне компонента или для конечной точки), и тогда такие ошибки полезной нагрузки JMS будут обнаружены, а тело сообщения будет установлено с сообщением об исключении;который вы можете настроить, и вызванное исключение на Exchange. Это позволяет обработчику ошибок маршрутизации Camel обнаруживать это как исключение и направлять в канал мертвых букв.

См. Тикет JIRA: https://issues.apache.org/jira/browse/CAMEL-14083

0 голосов
/ 17 октября 2019

После

  • много отладки и
  • попытки разных «созвездий» конфигурации маршрута (глобальные onException и специфичные для маршрута onException -определения)

Я понял, что с camel-jms-starter: 2.23.x и camel-jms-starter: 2.24.x проблема не может бытьрешил программным способом, так как я хочу сохранить флаг transacted=true. Я думаю, что это просто ошибка в camel-jms-starter , что возникающее исключение не обрабатывается моим сконфигурированным Route-ErrorHandler, но я не могу это изменить.

Итак, текущее решение для меня - установить механизм Poison-Message в связанном MQ-брокере. Таким образом, я выхожу из бесконечного цикла и могу направить сообщение в другую очередь.

Редактировать :
Даже если мне это не очень нравится, есть решениекоторые можно встроить в маршрут. Если я добавлю обработчик, выполненный по индивидуальному заказу, в маршрут, который просто перехватывает исключение во время преобразования тела, мой настроенный errorHandler будет запущен, и, поскольку это обработчик ошибок DLC, сообщение успешно используется, и у меня нет бесконечного цикла. Примечание. Использование convertBodyTo приводит к тому же неожиданному поведению, о котором говорилось в вопросе, поскольку оно использует тот же API. Процессор работает, потому что до этого момента тело обмена еще не трогалось.

Вот код:
Измененный маршрут:

    @Override
    public void configure() {
        errorHandler(deadLetterChannel(DLCRoute.ENDPOINT_DLC));

        // @formatter:off
        from(ENDPOINT_QUELLE).routeId(ROUTE_ALIAS)
            .removeHeaders("*", "JMS*")
            .process(myCustomConverter)
            .log(INFO, log, "Start Route: ${routeId}")
            .to("mock:mymock")
            .log(INFO, log, "Ende Route: ${routeId}")
        // @formatter:on
    } 

А вот myCustomConverterbean (с фиктивной реализацией):

@Component
public class MyCustomConverter implements Processor {

    private static final Logger LOG = LoggerFactory.getLogger(MyCustomConverter.class);
    @Override
    public void process(Exchange exchange) throws Exception {
        try {
            exchange.getIn().getBody(String.class);
        } catch( Exception ex) {
            LOG.error("Logging for the error");
            exchange.getIn().setBody(""); // TODO: Do something which makes sense
        }
    }
}

Причина, по которой мне не нравится этот обходной путь, заключается в том, что в будущей версии фреймворк может хорошо справиться с той же ситуацией, и мне придется внести изменения вкод для удаления этого обходного пути. Так что для меня конфигурация сообщения Пуассона - это путь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...