1

I have some method with reactive chain:

log.info("start");
Flux.fromIterable(cards)
                .flatMap(card -> {
                    log.info("some logs");
                    return externalService.sendCardInfo(card)
                            .flatMap(resp -> Mono.just(Tuples.of(resp, card)));
                })
                .flatMap(pair -> {
                    ResponseEntity<HttpStatus> resp = pair.getT1();
                    if (resp.getStatusCode().is2xxSuccessful()) {
                        log.info("some logs2");
                        // do and return smth
                    } else {
                        log.error("some logs3");
                        throw Exception();
                    }
                })
                .doOnComplete(() -> {
                    log.info("some logs4");
                    // do and return smth
                })
                .onErrorMap(e -> e)
                .subscribe();

Logs have MDC context with traceId in my project:

2022-04-28 16:45:20.111 traceid[a974a5dd-6b47-4fa0-9feb-261db64f1a18] INFO 145376 --- [ scheduling-1] r.g.o.o.g.p.s.ClassName : start

But after flatMap context are missing and I have

2022-04-28 16:45:20.200 traceid[ ] INFO 145376 --- [ scheduling-1] r.g.o.o.g.p.s.ClassName : some logs

I found next solution:

Map<String, String> contextMap = MDC.getCopyOfContextMap();
Flux.fromIterable(cards)
                .flatMap(card -> {
                    MDC.setContextMap(contextMap);
                    log.info("some logs");
                    return externalService.sendCardInfo(card)
                            .flatMap(resp -> Mono.just(Tuples.of(resp, card)));
                })
                .flatMap(pair -> {
                    MDC.setContextMap(contextMap);
                    ResponseEntity<HttpStatus> resp = pair.getT1();
                    if (resp.getStatusCode().is2xxSuccessful()) {
                        log.info("some logs2");
                        // do and return smth
                    } else {
                        log.error("some logs3");
                        throw Exception();
                    }
                })
                .doOnComplete(() -> {
                    MDC.setContextMap(contextMap);
                    log.info("some logs4");
                    // do and return smth
                })
                .onErrorMap(e -> e)
                .subscribe();

I don`t like this way and I want to forward context without any external maps. How can I do this?

Anton
  • 57
  • 8
  • 2
    MDC uses `ThreadLocal` in its implementation which does not work with webflux as it does not use the "one thread per request" model. Webflux uses an event loop in which a single thread can handle multiple requests concurrently. – Michael McFadyen Apr 28 '22 at 14:45
  • You can "hide" manual passing MDC context by implementing custom thread pool executor (or using MdcTaskDecorator https://moelholm.com/blog/2017/07/24/spring-43-using-a-taskdecorator-to-copy-mdc-data-to-async-threads). Then you can set this executor to Flux sheduller (Schedulers.fromExecutorService(ExecutorService)) – JustAnotherCoder Apr 28 '22 at 15:01

0 Answers0