Fix reply producing to not block reactive thread

When `DirectChannel` is used for reply producing, the data is
handled on the same thread which has produced it (normally), so
if we have a request-reply afterwards (e.g. `gateway()`), this thread
is blocked waiting for reply.
When the thread is assumed to be non-blocked (e.g. Netty event loop),
the request-reply withing such a thread for the same non-blocking client
causes a deadlock: the thread waits for reply, but at the same time it
supposes to fulfil a synchronization barrier with that reply

* Fix `AbstractMessageProducingHandler.asyncNonReactiveReply()` to use
a `publishOn(Schedulers.boundedElastic())` for reply `Mono` to free
producing thread from potential downstream blocking
* Demonstrate deadlock with a new test in the `RSocketDslTests`;
the original report was against WebFlux, but conditions are really
the same: `reactor-netty` is used as a low-level client

**Cherry-pick to `5.4.x`**
This commit is contained in:
Artem Bilan
2021-09-10 17:23:01 -04:00
committed by Gary Russell
parent fe300ebc38
commit 0f2285d5a3
2 changed files with 50 additions and 3 deletions

View File

@@ -55,6 +55,7 @@ import org.springframework.util.concurrent.SettableListenableFuture;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
/**
* The base {@link AbstractMessageHandler} implementation for the {@link MessageProducer}.
@@ -362,7 +363,9 @@ public abstract class AbstractMessageProducingHandler extends AbstractMessageHan
else {
reactiveReply = Mono.from((Publisher<?>) reply);
}
reactiveReply.subscribe(settableListenableFuture::set, settableListenableFuture::setException);
reactiveReply
.publishOn(Schedulers.boundedElastic())
.subscribe(settableListenableFuture::set, settableListenableFuture::setException);
future = settableListenableFuture;
}
future.addCallback(new ReplyFutureCallback(requestMessage, replyChannel));