Skip to content

Instantly share code, notes, and snippets.

@wreulicke
Last active April 24, 2024 17:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wreulicke/f63e0b2a4cb481680c35710e3dce2af6 to your computer and use it in GitHub Desktop.
Save wreulicke/f63e0b2a4cb481680c35710e3dce2af6 to your computer and use it in GitHub Desktop.
ExecutorService/ScheduledExecutorServiceでMDC引き回すやつ
package com.github.wreulicke.mdc;
import org.slf4j.MDC;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
public class DelegatingMDCInheritableExecutorService extends AbstractExecutorService {
private final ExecutorService delegate;
public DelegatingMDCInheritableExecutorService(ExecutorService delegate) {
this.delegate = delegate;
}
private Runnable decorate(Runnable runnable) {
Map<String, String> context = MDC.getCopyOfContextMap();
return () -> {
Map<String, String> original = MDC.getCopyOfContextMap();
if (context == null) {
MDC.clear();
} else {
MDC.setContextMap(context);
}
try {
runnable.run();
} finally {
if (original == null) {
MDC.clear();
} else {
MDC.setContextMap(original);
}
}
};
}
// delegates
@Override
public void shutdown() {
delegate.shutdown();
}
@Override
public List<Runnable> shutdownNow() {
return delegate.shutdownNow();
}
@Override
public boolean isShutdown() {
return delegate.isShutdown();
}
@Override
public boolean isTerminated() {
return delegate.isTerminated();
}
@Override
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
return delegate.awaitTermination(timeout, unit);
}
@Override
public void execute(Runnable command) {
delegate.execute(decorate(command));
}
}
package com.github.wreulicke.mdc;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.MDC;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static org.junit.jupiter.api.Assertions.*;
class DelegatingMDCInheritableExecutorServiceTest {
ExecutorService sut = new DelegatingMDCInheritableExecutorService(Executors.newSingleThreadExecutor());
@BeforeEach
void setUp() {
MDC.put("key", "value");
}
@AfterEach
void tearDown() {
MDC.clear();
}
@Test
void execute() {
sut.execute(() -> {
assertEquals("value", MDC.get("key"));
System.out.println("here");
});
}
@Test
void submitWithRunnable() throws ExecutionException, InterruptedException {
sut.submit(() -> {
assertEquals("value", MDC.get("key"));
}).get();
}
@Test
void submitWithCallable() throws ExecutionException, InterruptedException {
String actual = sut.submit(() -> MDC.get("key")).get();
assertEquals("value", actual);
}
@Test
void invokeAll() throws InterruptedException, ExecutionException {
Object actual = sut.invokeAll(Collections.singleton(() -> MDC.get("key"))).get(0).get();
assertEquals("value", actual);
}
@Test
void invokeAny() throws ExecutionException, InterruptedException {
Object actual = sut.invokeAny(Collections.singleton(() -> MDC.get("key")));
assertEquals("value", actual);
}
}
package com.github.wreulicke.mdc;
import org.slf4j.MDC;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
public class DelegatingMDCInheritableScheduledExecutorService extends AbstractExecutorService implements ScheduledExecutorService {
private final ScheduledExecutorService delegate;
public DelegatingMDCInheritableScheduledExecutorService(ScheduledExecutorService delegate) {
this.delegate = delegate;
}
// delegates
@Override
public void shutdown() {
delegate.shutdown();
}
@Override
public List<Runnable> shutdownNow() {
return delegate.shutdownNow();
}
@Override
public boolean isShutdown() {
return delegate.isShutdown();
}
@Override
public boolean isTerminated() {
return delegate.isTerminated();
}
@Override
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
return delegate.awaitTermination(timeout, unit);
}
@Override
public void execute(Runnable command) {
delegate.execute(decorate(command));
}
private <T> Callable<T> decorate(Callable<T> callable) {
Map<String, String> context = MDC.getCopyOfContextMap();
return () -> {
Map<String, String> original = MDC.getCopyOfContextMap();
if (context == null) {
MDC.clear();
} else {
MDC.setContextMap(context);
}
try {
return callable.call();
} finally {
if (original == null) {
MDC.clear();
} else {
MDC.setContextMap(original);
}
}
};
}
private Runnable decorate(Runnable runnable) {
Map<String, String> context = MDC.getCopyOfContextMap();
return () -> {
Map<String, String> original = MDC.getCopyOfContextMap();
if (context == null) {
MDC.clear();
} else {
MDC.setContextMap(context);
}
try {
runnable.run();
} finally {
if (original == null) {
MDC.clear();
} else {
MDC.setContextMap(original);
}
}
};
}
@Override
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
return delegate.schedule(decorate(command), delay, unit);
}
@Override
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
return delegate.schedule(decorate(callable), delay, unit);
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
return delegate.scheduleAtFixedRate(decorate(command), initialDelay, period, unit);
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
return delegate.scheduleAtFixedRate(decorate(command), initialDelay, delay, unit);
}
}
package com.github.wreulicke.mdc;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.MDC;
import java.util.concurrent.*;
import static org.junit.jupiter.api.Assertions.*;
class DelegatingMDCInheritableScheduledExecutorServiceTest {
ScheduledExecutorService sut = new DelegatingMDCInheritableScheduledExecutorService(Executors.newScheduledThreadPool(1));
@BeforeEach
void setUp() {
MDC.put("key", "value");
}
@AfterEach
void tearDown() {
MDC.clear();
}
@Test
void schedule() throws ExecutionException, InterruptedException {
sut.schedule(() -> {
assertEquals("value", MDC.get("key"));
}, 0, TimeUnit.SECONDS).get();
}
@Test
void scheduleWithCallable() throws ExecutionException, InterruptedException {
String actual = sut.schedule(() -> MDC.get("key"), 0, TimeUnit.SECONDS).get();
assertEquals("value", actual);
}
@Test
void scheduleAtFixedRate() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
ScheduledFuture<?> future = sut.scheduleAtFixedRate(() -> {
assertEquals("value", MDC.get("key"));
latch.countDown();
}, 0, 1000, TimeUnit.SECONDS);
latch.await();
future.cancel(true);
}
@Test
void scheduleWithFixedDelay() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
ScheduledFuture<?> future = sut.scheduleWithFixedDelay(() -> {
assertEquals("value", MDC.get("key"));
latch.countDown();
}, 0, 1000, TimeUnit.SECONDS);
latch.await();
future.cancel(true);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment