У меня есть приложение Spring Boot с запланированными заданиями, вызывающими асинхронные методы. Запланированный метод автоматически получает идентификатор трассировки, но он не распространяется на асинхронные методы, если я вручную не создаю диапазоны в асинхронных методах. Мне нужно, чтобы каждое запланированное выполнение имело один идентификатор трассировки, общий для всех операций, с разными идентификаторами диапазона для каждой асинхронной операции.
Текущая настройка:
Spring Boot 3.5.4 Micrometer 1.15.2 с Brave Bridge для отслеживания Log4j2 с MDC для структурированного ведения журнала ThreadPoolTaskExecutor для асинхронной обработки
Есть ли способ реализовать мой текущий подход чище, выглядит надежно?
Вот код
Это то, что я делаю прямо сейчас, кажется, работает, выглядит правильно? Вы видите какие-либо проблемы? Возможно ли более чистое решение?
AsyncConfig.java
import io.micrometer.context.ContextSnapshot;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
@EnableAsync
public class AsyncConfig {
public static final String THREAD_POOL_NAME = "threadPoolTaskExecutor";
@Value("${thread-pools.data-poller.max-size:10}")
private int threadPoolMaxSize;
@Value("${thread-pools.data-poller.core-size:5}")
private int threadPoolCoreSize;
@Value("${thread-pools.data-poller.queue-capacity:100}")
private int threadPoolQueueSize;
@Bean(name = THREAD_POOL_NAME)
public ThreadPoolTaskExecutor getThreadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(threadPoolMaxSize);
executor.setCorePoolSize(threadPoolCoreSize);
executor.setQueueCapacity(threadPoolQueueSize);
// Add context propagation
executor.setTaskDecorator(runnable ->
ContextSnapshot.captureAll().wrap(runnable)
);
return executor;
}
}
DataProcessor.java
import io.micrometer.tracing.Span;
import io.micrometer.tracing.Tracer;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@RequiredArgsConstructor
public class DataProcessor {
@NonNull
private final Tracer tracer;
public static final String THREAD_POOL_NAME = "threadPoolTaskExecutor";
@Async(THREAD_POOL_NAME)
public void processPendingData() {
Span span = tracer.nextSpan().name("process-pending-data").start();
try (Tracer.SpanInScope ws = tracer.withSpan(span)) {
log.info("Processing pending items");
// Now shows correct traceId and unique spanId!
// Business logic here
} finally {
span.end();
}
}
@Async(THREAD_POOL_NAME)
public void processRetryData() {
Span span = tracer.nextSpan().name("process-retry-data").start();
try (Tracer.SpanInScope ws = tracer.withSpan(span)) {
log.info("Processing retry items");
// Now shows correct traceId and unique spanId!
// Retry logic here
} finally {
span.end();
}
}
}
PollingService.java
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@EnabledScheduling
@RequiredArgsConstructor
public class PollingService {
@NonNull
private final DataProcessor dataProcessor;
// the trace id automatically spawns for this
@Scheduled(fixedDelay = 5000)
public void pollData() {
log.info("Starting data polling");
// Shows traceId and spanId correctly in logs
// These async calls lose trace context
dataProcessor.processPendingData();
dataProcessor.processRetryData();
}
}
Подробнее здесь: https://stackoverflow.com/questions/798 ... led-method
Микрометрическая трассировка для асинхронного метода и запланированного метода ⇐ JAVA
Программисты JAVA общаются здесь
1761904649
Anonymous
У меня есть приложение Spring Boot с запланированными заданиями, вызывающими асинхронные методы. Запланированный метод автоматически получает идентификатор трассировки, но он не распространяется на асинхронные методы, если я вручную не создаю диапазоны в асинхронных методах. Мне нужно, чтобы каждое запланированное выполнение имело один идентификатор трассировки, общий для всех операций, с разными идентификаторами диапазона для каждой асинхронной операции.
Текущая настройка:
Spring Boot 3.5.4 Micrometer 1.15.2 с Brave Bridge для отслеживания Log4j2 с MDC для структурированного ведения журнала ThreadPoolTaskExecutor для асинхронной обработки
Есть ли способ реализовать мой текущий подход чище, выглядит надежно?
Вот код
Это то, что я делаю прямо сейчас, кажется, работает, выглядит правильно? Вы видите какие-либо проблемы? Возможно ли более чистое решение?
AsyncConfig.java
import io.micrometer.context.ContextSnapshot;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
@EnableAsync
public class AsyncConfig {
public static final String THREAD_POOL_NAME = "threadPoolTaskExecutor";
@Value("${thread-pools.data-poller.max-size:10}")
private int threadPoolMaxSize;
@Value("${thread-pools.data-poller.core-size:5}")
private int threadPoolCoreSize;
@Value("${thread-pools.data-poller.queue-capacity:100}")
private int threadPoolQueueSize;
@Bean(name = THREAD_POOL_NAME)
public ThreadPoolTaskExecutor getThreadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(threadPoolMaxSize);
executor.setCorePoolSize(threadPoolCoreSize);
executor.setQueueCapacity(threadPoolQueueSize);
// Add context propagation
executor.setTaskDecorator(runnable ->
ContextSnapshot.captureAll().wrap(runnable)
);
return executor;
}
}
DataProcessor.java
import io.micrometer.tracing.Span;
import io.micrometer.tracing.Tracer;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@RequiredArgsConstructor
public class DataProcessor {
@NonNull
private final Tracer tracer;
public static final String THREAD_POOL_NAME = "threadPoolTaskExecutor";
@Async(THREAD_POOL_NAME)
public void processPendingData() {
Span span = tracer.nextSpan().name("process-pending-data").start();
try (Tracer.SpanInScope ws = tracer.withSpan(span)) {
log.info("Processing pending items");
// Now shows correct traceId and unique spanId!
// Business logic here
} finally {
span.end();
}
}
@Async(THREAD_POOL_NAME)
public void processRetryData() {
Span span = tracer.nextSpan().name("process-retry-data").start();
try (Tracer.SpanInScope ws = tracer.withSpan(span)) {
log.info("Processing retry items");
// Now shows correct traceId and unique spanId!
// Retry logic here
} finally {
span.end();
}
}
}
PollingService.java
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@EnabledScheduling
@RequiredArgsConstructor
public class PollingService {
@NonNull
private final DataProcessor dataProcessor;
// the trace id automatically spawns for this
@Scheduled(fixedDelay = 5000)
public void pollData() {
log.info("Starting data polling");
// Shows traceId and spanId correctly in logs
// These async calls lose trace context
dataProcessor.processPendingData();
dataProcessor.processRetryData();
}
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79805315/micrometer-trace-for-async-method-and-scheduled-method[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия