Files
digital-garden/dev/java/quarkus/Обеспечение корректного асинхронного выполнения в Quarkus.md
Struchkov Mark ee66c043b8
All checks were successful
continuous-integration/drone/push Build is passing
Обновление
2025-02-25 21:32:31 +03:00

5.2 KiB
Raw Blame History

aliases, tags, date
aliases tags date
maturity/🌱
content/problem
2025-02-24

В процессе разработки одного из сервисов я обнаружил, что при асинхронной обработке данных с почтового сервера терялась диагностическая информация, передаваемая через ../../Mapped Diagnostic Context.

Первоначально код выглядел как-то так:

Unis.voidItem()
    .chain(() -> mailService.process(msg));

Возникающие проблемы:

  • Потеря MDC: MDC хранится в ThreadLocal, а асинхронные операции могут переключаться между потоками. Из-за этого данные, установленные в MDC, терялись или оказывались перепутанными, что усложняло диагностику.
  • Отсутствие изоляции: Поскольку вызов выполнялся в общем контексте, отсутствовало явное управление окружением выполнения. Это могло привести к состояниям гонки или другим непредсказуемым ошибкам.
  • Блокировка ../../architecture/Event Loop: Если метод mailService.process выполнял блокирующий код, это могло негативно сказаться на производительности.

Стоит подчеркнуть, что если бы запрос поступал через стандартные механизмы ../../../meta/zero/00 Quarkus (gRPC, GraphQL, Kafka), то управление контекстом осуществлялось бы системой, и подобных проблем бы не возникало. Однако в нашем случае вызов инициировался через org.apache.camel.Processor, что требовало дополнительных усилий по сохранению контекстной информации.

Анализ показал, что основная проблема кроется в потере MDC при переключении между потоками. В условиях асинхронного выполнения вызовы, инициированные через Camel, не гарантируют автоматическую передачу контекста, что приводит к потере данных, необходимых для корректного логирования и диагностики.

==Чтобы решить эту проблему, было решено явно создать дублированный контекст и переключить выполнение на него.== Код был изменён следующим образом:

final Context duplicateContext = Context.newInstance(
    VertxContext.getOrCreateDuplicatedContext(vertx.getDelegate())
);
Unis.voidItem()
    .emitOn(duplicateContext::runOnContext)
    .chain(() -> mailService.process(msg));

Преимущества данного подхода:

  • Сохранение MDC: Дублированный контекст позволяет перенести все данные, связанные с текущим окружением (включая MDC), что обеспечивает корректное логирование даже при асинхронном выполнении.
  • Изоляция выполнения: Переключение на новый контекст гарантирует, что все последующие операции выполняются в заданном окружении, исключая неожиданные переключения потоков.
  • Устранение блокировки ../../architecture/Event Loop: Если метод mailService.process содержит блокирующие или ресурсоёмкие операции, их выполнение в изолированном контексте помогает снизить негативное влияние на основной event loop.

Таким образом, если ваши асинхронные операции инициируются через нестандартные компоненты, такие как Apache Camel, и Quarkus не управляет контекстом напрямую, создание дублированного контекста становится необходимым для корректной работы.


Мета информация

Область:: ../../../meta/zero/00 Quarkus Родитель:: Источник:: Создана:: 2025-02-24 Автор::

Дополнительные материалы

Дочерние заметки