Recently I came across the problem of ThreadLocal context in multithreaded environment.
If the Thread that handled a request uses an Executor
to asynchronously execute tasks, the ThreadLocal context is lost and information such as requestId will be be missing in the logs.
We can solve this using the Decorator pattern:
Wrap Runnable to preserve caller Thread’s context
Implement ExecutorDecorator that wraps every execution
Additional: Configure Spring’s @Async to use Decorator
There is a small sample application on Github. It has a service, which
has an @Async method. After startup, the service is called 10 times with a specific MDC context containing the loop-count and
the caller’s threadId. The asynchronous service method prints its MDC to the log, which should contain the original mentioned properties.
Without our ContextAwareExecutorDecorator, we will encounter the initially described problem: the ThreadLocal context gets lost.
In that case the log looks like this:
If we now wrap the Executor into our ContextAwareExecutorDecorator, as described in Step 3, the problem will be solved.
The resulting log looks like this: