athom
athom

Reputation: 1598

Mono gets OnCancel instead of OnSuccessOrError after successful request

I have a SpringBoot Webflux app which implements a WebFilter to log success/error once a Publisher completes. My Webfilter is similar to the following:

public class MyFilter implements WebFilter {

private static final Logger LOG = LoggerFactory.getLogger(MyFilter.class);

@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
    return chain.filter(exchange)
            .doOnCancel(() -> {
                LOG.info("Cancelled");
            })
            .doOnSuccess(aVoid -> {
                LOG.info("Success");
            })
            .doOnSuccessOrError((aVoid, throwable) -> {
                if (throwable == null) {
                    LOG.info("Completed successfully");
                } else {
                    LOG.error("An error occurred", throwable);
                }
            });
}

Since SpringBoot 2.1.5, the WebFilter does not work as expected anymore. Instead of getting the doOnSuccessOrError event I now get doOnCancel. This only happens when using Netty since version 0.8.7. When using Undertow, it works as expected.

In all cases the Web requests completes successfully, returning the correct data to the client.

Please see DEBUG/TRACE logs below:

[reactor-http-nio-3] DEBUG o.s.h.codec.json.Jackson2JsonEncoder - [6bfed744] Encoding [{"errors":[]}]
[reactor-http-nio-3] DEBUG r.n.http.server.HttpServerOperations - [id: 0x6bfed744, L:/0:0:0:0:0:0:0:1:8071 - R:/0:0:0:0:0:0:0:1:55927] Decreasing pending responses, now 0
[reactor-http-nio-3] DEBUG r.n.http.server.HttpServerOperations - [id: 0x6bfed744, L:/0:0:0:0:0:0:0:1:8071 - R:/0:0:0:0:0:0:0:1:55927] Last HTTP packet was sent, terminating the channel
[reactor-http-nio-3] TRACE r.netty.channel.ChannelOperations - [id: 0x6bfed744, L:/0:0:0:0:0:0:0:1:8071 - R:/0:0:0:0:0:0:0:1:55927] Disposing ChannelOperation from a channel
java.lang.Exception: ChannelOperation terminal stack
    at reactor.netty.channel.ChannelOperations.terminate(ChannelOperations.java:391)
    at reactor.netty.http.server.HttpServerOperations.cleanHandlerTerminate(HttpServerOperations.java:519)
    at reactor.netty.http.server.HttpTrafficHandler.operationComplete(HttpTrafficHandler.java:314)
    at reactor.netty.http.server.HttpTrafficHandler.operationComplete(HttpTrafficHandler.java:54)
    at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:502)
    at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:476)
    at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:415)
    at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:540)
    at io.netty.util.concurrent.DefaultPromise.setSuccess0(DefaultPromise.java:529)
    at io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:101)
    at io.netty.util.internal.PromiseNotificationUtil.trySuccess(PromiseNotificationUtil.java:48)
    at io.netty.channel.ChannelOutboundBuffer.safeSuccess(ChannelOutboundBuffer.java:715)
    at io.netty.channel.ChannelOutboundBuffer.remove(ChannelOutboundBuffer.java:270)
    at io.netty.channel.ChannelOutboundBuffer.removeBytes(ChannelOutboundBuffer.java:350)
    at io.netty.channel.socket.nio.NioSocketChannel.doWrite(NioSocketChannel.java:411)
    at io.netty.channel.AbstractChannel$AbstractUnsafe.flush0(AbstractChannel.java:939)
    at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.flush0(AbstractNioChannel.java:360)
    at io.netty.channel.AbstractChannel$AbstractUnsafe.flush(AbstractChannel.java:906)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.flush(DefaultChannelPipeline.java:1370)
    at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:749)
    at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:741)
    at io.netty.channel.AbstractChannelHandlerContext.flush(AbstractChannelHandlerContext.java:727)
    at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.flush(CombinedChannelDuplexHandler.java:533)
    at io.netty.channel.ChannelOutboundHandlerAdapter.flush(ChannelOutboundHandlerAdapter.java:125)
    at io.netty.channel.CombinedChannelDuplexHandler.flush(CombinedChannelDuplexHandler.java:358)
    at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:749)
    at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:741)
    at io.netty.channel.AbstractChannelHandlerContext.flush(AbstractChannelHandlerContext.java:727)
    at io.netty.channel.ChannelDuplexHandler.flush(ChannelDuplexHandler.java:127)
    at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:749)
    at io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush(AbstractChannelHandlerContext.java:764)
    at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:789)
    at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:757)
    at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:812)
    at io.netty.channel.DefaultChannelPipeline.writeAndFlush(DefaultChannelPipeline.java:1036)
    at io.netty.channel.AbstractChannel.writeAndFlush(AbstractChannel.java:305)
     ...
[reactor-http-nio-3] INFO  c.m.d.MyFilter - Cancelled
[reactor-http-nio-3] DEBUG r.n.channel.ChannelOperationsHandler - [id: 0x6bfed744, L:/0:0:0:0:0:0:0:1:8071 - R:/0:0:0:0:0:0:0:1:55927] No ChannelOperation attached. Dropping: EmptyLastHttpContent

Upvotes: 1

Views: 1233

Answers (1)

Brian Clozel
Brian Clozel

Reputation: 59056

This is a known issue in Spring Framework (see spring-framework#22952) and especially Reactor Netty (reactor-netty#741). There is no known workaround for that right now.

Upvotes: 2

Related Questions