Сценарий потери сообщения Spring интеграции

Сводка - потеря сообщения при систематическом завершении работы приложения.

У меня есть приложение, написанное с использованием Spring интеграции, и я использую запросы от внешних систем с помощью jms: message-driven-channel-adapter. Это конфигурация адаптера канала -

<jms:message-driven-channel-adapter id = "InboundAdapter" destination = "InQueue"
                                        connection-factory = "connectionFactory"
                                        channel = "responseChannel"
                                        error-channel = "errorChannel"
                                        acknowledge = "transacted"
                                        receive-timeout = "50000"
                                        auto-startup = "true"/>

мой канал ответа выглядит так -

 <int:chain id = "processorChain" input-channel = "responseChannel">
        <int:service-activator method = "doProcess" ref = "inputProcessor" />

        <int:router id = "inputRouter" method = "route">
            <int:mapping value = "REQUIRED" channel = "builderChannel"/>
            <int:mapping value = "NOT_REQUIRED" channel = "TerminateChannel"/>
            <bean id = "Router" class = "xxx.xxx.Router">
            </bean>
        </int:router>
    </int:chain>

Теперь, когда я выполняю kill -9 pid, я вижу, что сообщение откатывается в очередь, и все в порядке. Но когда я выполняю kill pid, сообщение где-то теряется. Я включил журналы jms и вижу, что прослушиватель JMS ожидает завершения передачи сообщения перед закрытием потребителя JMS, но все же я не возвращаю сообщение в мою очередь. Это фрагмент журнала, который я вижу в своих журналах.

trace: 15.11.18 15: 42: 46.619 [Thread-10] DEBUG org.springframework.jms.listener.DefaultMessageListenerContainer - Ожидание завершения работы вызывающих прослушивателей сообщений трассировка: 15.11.18 15: 42: 46.619 [Thread-10] DEBUG org.springframework.jms.listener.DefaultMessageListenerContainer - все еще ожидает завершения работы 1 вызывающих обработчиков сообщений (итерация 0)

После регистрации он вызывает активаторы службы, указанные в канале ответа.

Может ли кто-нибудь пролить свет на приведенное выше поведение, я ожидал, что, когда мы выдадим команду kill, все сообщения, которые находятся в пути, должны быть возвращены в очередь, вместо этого он пытается вызвать активаторы, определенные с помощью in channel и после вызова последнего компонента, который является маршрутизатором, он просто завершает работу.

Любая помощь по этой теме будет действительно полезна !!


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

<int:chain input-channel = "inputchain">
    <int:transformer id = "xxx" method = "transform">
        <bean class = "xxx" />
    </int:transformer>

    <int:service-activator  id = "xxx" method = "doProcess">
        <bean class = "xx">
            <constructor-arg ref = "xxx"/>
        </bean>
    </int:service-activator>

    <int:service-activator id = "xxx" ref = "rulesProcessor" method = "doProcess"/>
    <int:service-activator id = "xxx" ref = "xxx" method = "doProcess"/>

    <!-- Existing Flow Continues -->
    <int:router id = "xxxRequiredRouter" method = "xxxRequired">
        <int:mapping value = "Required" channel = "firstChannel"/>
        <int:mapping value = "NotRequired" channel = "secondChannel"/>
        <bean id = "xxxRouter" class = "xxx.Router" />
        </bean>
    </int:router>

</int:chain>

<int:chain input-channel = "secondChannel">

   some logic

</int:chain>

Таким образом, поток завершает эту цепочку и изящно выходит. Он не называет мою следующую цепочку "secondChannel". Граница моей транзакции не заканчивается в этой цепочке inputchain, она заканчивается в конце secondChannel. Итак, я не отправил эту транзакцию в базу данных, поскольку граница транзакции находится в конце следующей цепочки, поэтому это недоступно в БД, и приложение думает, что выполнение цепочки завершено, поэтому оно завершено, поэтому оно не откатывается до очереди также. В конце концов, у меня нет этого сообщения в моей базе данных и его нет в очереди.

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

Почему вы говорите "потеря сообщения", если в конце объясните, что все идет хорошо до роутера? Я бы сказал, что это совершенно нормальное поведение, когда мы вызываем команду «Стоп», но пусть задачи в полете должны быть выполнены.

Artem Bilan 15.11.2018 17:48

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

Vaibs 16.11.2018 10:27

Если весь ваш процесс находится в одном потоке, я бы предложил использовать JmsTransactionManager для этого <jms:message-driven-channel-adapter>. Кроме того, поскольку вы упомянули основанные на данных, возможно, даже лучше обернуть оба менеджера транзакций в ChainedTransactionManager. См. Здесь для получения дополнительной информации: javaworld.com/article/2077963/open-source-tools/…

Artem Bilan 16.11.2018 18:17
1
3
296
1

Ответы 1

SIGTERM kill будет ждать, пока поток завершит свою работу.

В конце концов контейнер прервет его, но это поможет, только если он будет делать что-то, что можно прервать.

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

Vaibs 16.11.2018 10:31

Это невозможно, если поток не застрял в каком-то непрерывном коде и никогда не возвращается в контейнер, а JVM никогда не завершает работу.

Gary Russell 16.11.2018 16:04

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

Vaibs 20.11.2018 10:10

В этом не должно быть необходимости; Если вы можете опубликовать где-нибудь небольшой проект, который воспроизводит это поведение, я посмотрю на него.

Gary Russell 20.11.2018 14:58

После некоторой отладки и ударов головой о системе я нашел точный сценарий, в котором это происходит. Я обновил актуальную проблему с выводами.

Vaibs 21.11.2018 17:36

У меня возникли проблемы с синтаксическим анализом вашего объяснения «поскольку граница транзакции находится в конце следующей цепочки». Нет причин, по которым мы не будем выполнять маршрутизацию ко второй цепочке, если только secondChannel не является очередью или каналом исполнителя, что не имеет смысла, поскольку тогда не будет участвовать в сделке. Как я уже сказал, опубликуйте полный пример, демонстрирующий поведение, и я посмотрю; Я не могу «угадать», как выглядит остальная часть вашего потока.

Gary Russell 21.11.2018 17:48

Спасибо, Гэри, я работаю над образцом приложения, которое я могу отправить. А пока вы можете сказать мне, есть ли у вас представление об этом - когда запускается завершение работы, я вижу это сообщение в журналах - EventDrivenConsumer - Удаление {chain: secondChain} в качестве подписчика на канал 'secondChannel' остановило secondChain и MessageDeliveryException: У Dispatcher нет подписчиков на канал secondChannel. Это происходит до закрытия JMS-соединений, поэтому я предполагаю, что это причина того, что сообщение не было перенаправлено на этот канал (secondChannel), поскольку оно уже было остановлено.

Vaibs 22.11.2018 16:15

Правильно; это имеет смысл - контекст приложения закрывается, поэтому конечные точки отписываются. Диспетчер не имеет подписчиков, исключение вызовет откат транзакции и возврат сообщения в очередь. Итак, опять же, потеря сообщения не должна происходить.

Gary Russell 22.11.2018 16:24

Другие вопросы по теме