57 lines
5.2 KiB
Markdown
57 lines
5.2 KiB
Markdown
---
|
||
aliases:
|
||
tags:
|
||
- maturity/🌱
|
||
- content/problem
|
||
date: 2025-02-24
|
||
---
|
||
В процессе разработки одного из сервисов я обнаружил, что при асинхронной обработке данных с почтового сервера терялась диагностическая информация, передаваемая через [[../../Mapped Diagnostic Context|MDC]].
|
||
|
||
Первоначально код выглядел как-то так:
|
||
|
||
```java
|
||
Unis.voidItem()
|
||
.chain(() -> mailService.process(msg));
|
||
```
|
||
|
||
**Возникающие проблемы:**
|
||
- **Потеря MDC:** MDC хранится в ThreadLocal, а асинхронные операции могут переключаться между потоками. Из-за этого данные, установленные в MDC, терялись или оказывались перепутанными, что усложняло диагностику.
|
||
- **Отсутствие изоляции:** Поскольку вызов выполнялся в общем контексте, отсутствовало явное управление окружением выполнения. Это могло привести к состояниям гонки или другим непредсказуемым ошибкам.
|
||
- Блокировка [[../../architecture/Event Loop|event loop]]: Если метод `mailService.process` выполнял блокирующий код, это могло негативно сказаться на производительности.
|
||
|
||
Стоит подчеркнуть, что если бы запрос поступал через стандартные механизмы [[../../../meta/zero/00 Quarkus|Quarkus]] (gRPC, GraphQL, Kafka), то управление контекстом осуществлялось бы системой, и подобных проблем бы не возникало. Однако в нашем случае вызов инициировался через `org.apache.camel.Processor`, что требовало дополнительных усилий по сохранению контекстной информации.
|
||
|
||
Анализ показал, что основная проблема кроется в потере MDC при переключении между потоками. В условиях асинхронного выполнения вызовы, инициированные через Camel, не гарантируют автоматическую передачу контекста, что приводит к потере данных, необходимых для корректного логирования и диагностики.
|
||
|
||
==Чтобы решить эту проблему, было решено явно создать дублированный контекст и переключить выполнение на него.== Код был изменён следующим образом:
|
||
|
||
```java
|
||
final Context duplicateContext = Context.newInstance(
|
||
VertxContext.getOrCreateDuplicatedContext(vertx.getDelegate())
|
||
);
|
||
Unis.voidItem()
|
||
.emitOn(duplicateContext::runOnContext)
|
||
.chain(() -> mailService.process(msg));
|
||
```
|
||
|
||
**Преимущества данного подхода:**
|
||
- **Сохранение MDC:** Дублированный контекст позволяет перенести все данные, связанные с текущим окружением (включая MDC), что обеспечивает корректное логирование даже при асинхронном выполнении.
|
||
- **Изоляция выполнения:** Переключение на новый контекст гарантирует, что все последующие операции выполняются в заданном окружении, исключая неожиданные переключения потоков.
|
||
- Устранение блокировки [[../../architecture/Event Loop|event loop]]: Если метод `mailService.process` содержит блокирующие или ресурсоёмкие операции, их выполнение в изолированном контексте помогает снизить негативное влияние на основной event loop.
|
||
|
||
Таким образом, если ваши асинхронные операции инициируются через нестандартные компоненты, такие как Apache Camel, и Quarkus не управляет контекстом напрямую, создание дублированного контекста становится необходимым для корректной работы.
|
||
|
||
***
|
||
## Мета информация
|
||
**Область**:: [[../../../meta/zero/00 Quarkus|00 Quarkus]]
|
||
**Родитель**::
|
||
**Источник**::
|
||
**Создана**:: [[2025-02-24]]
|
||
**Автор**::
|
||
### Дополнительные материалы
|
||
-
|
||
|
||
### Дочерние заметки
|
||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||
|