MdcExecutor.java

  1. package no.nav.data.common.utils;

  2. import jakarta.annotation.PreDestroy;
  3. import jakarta.validation.constraints.NotNull;
  4. import org.slf4j.MDC;
  5. import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
  6. import org.springframework.util.concurrent.ListenableFutureCallback;

  7. import java.util.Map;
  8. import java.util.concurrent.SynchronousQueue;
  9. import java.util.concurrent.ThreadPoolExecutor;
  10. import java.util.concurrent.TimeUnit;
  11. import java.util.function.Consumer;

  12. public class MdcExecutor extends ThreadPoolExecutor {

  13.     public static MdcExecutor newThreadPool(int maximumPoolSize, String name) {
  14.         return new MdcExecutor(maximumPoolSize, name);
  15.     }

  16.     private MdcExecutor(int maximumPoolSize, String name) {
  17.         super(1, maximumPoolSize, 60L, TimeUnit.SECONDS, new SynchronousQueue<>(), new CustomizableThreadFactory(name + "-"));
  18.     }

  19.     @Override
  20.     public void execute(Runnable command) {
  21.         var parentContext = MDC.getCopyOfContextMap();
  22.         super.execute(wrap(command, parentContext));
  23.     }

  24.     public static <T> ListenableFutureCallback<? super T> wrap(Consumer<T> onSuccessCallback, Consumer<Throwable> onErrorCallback) {
  25.         var parentContext = MDC.getCopyOfContextMap();
  26.         return new ListenableFutureCallback<T>() {
  27.             @Override
  28.             public void onSuccess(T result) {
  29.                 wrap(() -> onSuccessCallback.accept(result), parentContext).run();
  30.             }

  31.             @Override
  32.             public void onFailure(@NotNull Throwable ex) {
  33.                 wrap(() -> onErrorCallback.accept(ex), parentContext).run();
  34.             }
  35.         };
  36.     }

  37.     private static Runnable wrap(Runnable runnable, Map<String, String> parentContext) {
  38.         return () -> {
  39.             var previous = MDC.getCopyOfContextMap();
  40.             if (parentContext == null) {
  41.                 MDC.clear();
  42.             } else {
  43.                 MDC.setContextMap(parentContext);
  44.             }
  45.             try {
  46.                 runnable.run();
  47.             } finally {
  48.                 if (previous == null) {
  49.                     MDC.clear();
  50.                 } else {
  51.                     MDC.setContextMap(previous);
  52.                 }
  53.             }
  54.         };
  55.     }

  56.     @Override
  57.     @PreDestroy
  58.     public void shutdown() {
  59.         super.shutdown();
  60.     }
  61. }