태스크데코레이터 (1)

비동기 처리시 로깅 uuid 설정

트래픽이 많은 환경에서 멀티쓰레드로 작업을 처리하고 있는데 각 쓰레드에 uuid 설정이 안되어 있어 로그상으로 확인이 불가한 경우가 생겼다. 기존에는 잘 되고 있었던 것이었고 뭔가 수정작업을 하면서 빼뜨린 것 같아 다른 쓰레드들의 설정을 보다가 TaskDecorator를 보게 되었다.

 

package com.keichee;

import org.slf4j.MDC;
import org.springframework.core.task.TaskDecorator;

import java.util.Map;

public class LoggingTaskDecorator implements TaskDecorator {

    @Override
    public Runnable decorate(Runnable task) {
        Map<String, String> callerThreadContext = MDC.getCopyOfContextMap();
        return () -> {
            MDC.setContextMap(callerThreadContext);
            task.run();
        };
    }
}

 

LoggingTaskDecorator는 TaskDecorator를 구현하고 있는데 decorate(Runnable task) 메서드만 구현해주면 된다.

여기서 TaskDecorator는 어떤 task(작업)을 꾸며준다는 의미로 지어진 이름이며 스프링의 코어 패키지에 들어있을 만큼 자주 사용되는 녀석이라고 생각하면 된다. 스프링 공식 문서에 따르면 TaskDecorator는 아래와 같이 설명이 되어있다.

 

Functional Interface : This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.@FunctionalInterface public interface TaskDecorator

A callback interface for a decorator to be applied to any Runnable about to be executed.

Note that such a decorator is not necessarily being applied to the user-supplied Runnable/Callable but rather to the actual execution callback (which may be a wrapper around the user-supplied task).

The primary use case is to set some execution context around the task's invocation, or to provide some monitoring/statistics for task execution.

Since:4.3

 

자, 그럼 TaskDecorator를 구현한 이 LoggingTaskDecorator는 어떻게 사용할까?

간단하다. 스프링에서 제공하는 ThreadPoolTaskExecutor를 사용한다면 setTaskDecorator() 메서드를 이용해 세팅해주기만 하면 된다.

@Bean
public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor t = new ThreadPoolTaskExecutor();
        t.setTaskDecorator(new LoggingTaskDecorator());
        return t;
}