5.2 KiB
aliases, tags, date
| aliases | tags | date | ||
|---|---|---|---|---|
|
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 Автор::