Micronaut WebSocketServer throws IllegalReferenceCountException

0

Heja,
zacząłem zabawę z Micronautem. Napisałem testowy WebSocketServer

@ServerWebSocket("/wbs/{user}")
public class WebSocketServer {

    private WebSocketBroadcaster broadcaster;

    public WebSocketServer(WebSocketBroadcaster broadcaster) {
        this.broadcaster = broadcaster;
    }

    @OnOpen
    public Publisher<String> onOpen(String user, WebSocketSession session) {
        String msg = "[" + user + "] Connected!";
        return broadcaster.broadcast(msg, isValid(user, session));
    }

    @OnMessage
    public Publisher<String> onMessage(String user, String message, WebSocketSession session) {
        String msg = "[" + user + "] Messaged: " + message;
        return broadcaster.broadcast(msg, isValid(user, session));
    }

    @OnClose
    public Publisher<String> onClose(String user, WebSocketSession session) {
        String msg = "[" + user + "] Disconnected!";
        return broadcaster.broadcast(msg, isValid(user, session));
    }

    private Predicate<WebSocketSession> isValid(String topic, WebSocketSession session) {
        return s -> s != session && topic.equalsIgnoreCase(s.getUriVariables().get("user", String.class, null));
    }

}

Do tego servera łączę się z innego projektu przy użyciu biblioteki Java-WebSocket

public class ExampleClient extends WebSocketClient {

    public ExampleClient(URI serverUri) {
        super(serverUri);
    }

    @Override
    public void onOpen(ServerHandshake serverHandshake) {
        send("Hello, it is me. Mario :)");
        System.out.println( "opened connection" );
    }

    @Override
    public void onMessage(String message) {
        System.out.println( "received: " + message );
    }

    @Override
    public void onClose( int code, String reason, boolean remote ) {
        System.out.println( "Connection closed by " + ( remote ? "remote peer" : "us" ) + " Code: " + code + " Reason: " + reason );
    }

    @Override
    public void onError(Exception ex) {
        ex.printStackTrace();
    }
}

Wszystko działa dobrze do czasu aż po jakimś czasie rzuci wyjątkiem

server: [Tester] Messaged: Hello, it is me. Mario :)
19:39:07.839 [nioEventLoopGroup-1-5] ERROR i.m.h.s.n.w.NettyServerWebSocketHandler - Unexpected Exception in WebSocket [pl.janda.crypto.WebSocketServer@54d18fdd]: refCnt: 0, decrement: 1
io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.util.internal.ReferenceCountUpdater.toLiveRealRefCnt(ReferenceCountUpdater.java:74)
    at io.netty.util.internal.ReferenceCountUpdater.release(ReferenceCountUpdater.java:138)
    at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:100)
    at io.netty.buffer.DefaultByteBufHolder.release(DefaultByteBufHolder.java:115)
    at io.netty.util.ReferenceCountUtil.release(ReferenceCountUtil.java:88)
    at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:106)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:321)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:295)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:834)
server: [Tester] Disconnected!

Czy macie pojęcie jaki jest powód oraz jak mogę go rozwiązać?

3

Generalnie jest to związane z mechanizmem Nettiego chroniącym przed memory leakiem. IMHO powody mogą być 2: bug w Micronaut albo używasz jakiegoś low-level API Nettiego i nie zamykasz buforu. Ew. pośrednio - Micronaut nie zamyka: https://stackoverflow.com/questions/59169871/micronaut-httpresponse-body-compositebytebuf-type-throws-io-netty-util-illegalre

0
Charles_Ray napisał(a):

Generalnie jest to związane z mechanizmem Nettiego chroniącym przed memory leakiem. IMHO powody mogą być 2: bug w Micronaut albo używasz jakiegoś low-level API Nettiego i nie zamykasz buforu. Ew. pośrednio - Micronaut nie zamyka: https://stackoverflow.com/questions/59169871/micronaut-httpresponse-body-compositebytebuf-type-throws-io-netty-util-illegalre

Dzięki za informację.
Najwidoczniej jest to bug w którejś z bibliotek. Zmieniłem libkę dla clienta na "org.eclipse.jetty.websocket" i problem ustąpił. Dociekać głębiej nie będę.

1 użytkowników online, w tym zalogowanych: 0, gości: 1