springspring-bootspring-batchmicrometer-tracing

Micrometer tracing: Propagate context to spring batch (spring boot 3) SimpleAsyncTaskExecutor tasks


I am using spring boot 3 / spring batch and I would like to propagate the context across the spring batch SimpleAsyncTaskExecutor steps for distributed tracing (micrometer). In my case, the main flow splits into parallel flow and back to main flow. I would like the trace id to be the same across all the parent and child flows. I noticed the steps in the main flow have the same trace id, but the parallel flows have a different trace id.

Please advise. Thanks

ps Took similar approach to answer below:

    @Bean
    public TaskDecorator taskFlowDecorator() {
        return new ContextPropagatingTaskDecorator();
    }

    @Bean("taskFlowExecutor")
    public TaskExecutor taskFlowExecutor(TaskDecorator taskFlowDecorator) {
        return new SimpleAsyncTaskExecutorBuilder()
                .threadNamePrefix("work-flow-")
                .taskDecorator(taskFlowDecorator)
                .build();
    }

Solution

  • The approach described in this answer could be adapted to propagate context (e.g. thread-local variables) to Spring Batch child flows or steps.

    If you want to have one traceId in all steps or flows of the Spring Batch job, then

    @Bean
    public TaskDecorator taskDecorator() {
        return new ContextPropagatingTaskDecorator();
    }
    
    @Bean
    public TaskExecutor taskExecutor(TaskDecorator taskDecorator) {
        var taskExecutor = new SimpleAsyncTaskExecutor();
        executor.setTaskDecorator(taskDecorator);
        return taskExecutor;
    }
    
    // example of flow
    FlowBuilder<SimpleFlow>("parallelFlow")
        .split(taskExecutor)
    // example of step
    StepBuilder("mainStep", jobRepository)
        ...
        .taskExecutor(taskExecutor)
    

    Another approach how to create a decorated executor suggested by the question's author:

    @Bean
    public TaskExecutor taskExecutor(TaskDecorator taskDecorator) {
        return new SimpleAsyncTaskExecutorBuilder()
            .threadNamePrefix("work-flow-")
            .taskDecorator(taskDecorator)
            .build();
    }