Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best way to reconnect after connection closed in Netty

Tags:

java

netty

Simple scenario:

  1. A lower level class A that extends SimpleChannelUpstreamHandler. This class is the workhorse to send the message and received the response.
  2. A top level class B that can be used by other part of the system to send and receive message (can simulate both Synchronous and Asynchronous). This class creates the ClientBootstrap, set the pipeline factory, invoke the bootstrap.connect() and eventually get a handle/reference of the class A through which to be used to send and receive message. Something like:

    ChannelFuture future = bootstrap.connect();
    Channel channel = future.awaitUninterruptibly().getChannel();
    

    A handler = channel.getPipeline().get(A.class);

I know in class A, I can override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e); so that when the remote server is down, I can be notified.

Since after channel is closed, the original class A reference (handler above) in class B is not valid anymore, so I need to replace it with a new reference.

Ideally, I want class A to have a mechanism to notify class B within the above overrided channelClosed method so the bootstrap.connect can be invoked again within class B. One way to do this is to have a reference in class A that reference class B. To do that, I would need to pass class B reference to the PipelineFactory and then have the PipelineFactory pass the reference of B to A.

Any other simpler way to achieve the same thing?

thanks,

like image 491
step-by-step Avatar asked Nov 02 '13 04:11

step-by-step


2 Answers

Channel.closeFuture() returns a ChannelFuture that will notify you when the channel is closed. You can add a ChannelFutureListener to the future in B so that you can make another connection attempt there.

You probably want to repeat this until the connection attempt succeeds finally:

private void doConnect() {
    Bootstrap b = ...;
    b.connect().addListener((ChannelFuture f) -> {
        if (!f.isSuccess()) {
            long nextRetryDelay = nextRetryDelay(...);
            f.channel().eventLoop().schedule(nextRetryDelay, ..., () -> {
                doConnect();
            }); // or you can give up at some point by just doing nothing.
        }
    });
}
like image 194
trustin Avatar answered Nov 10 '22 04:11

trustin


I don't know if this is the right solution but to fix the thread leak of trustin's solution I found I could shutdown the event loop after the scheduler had triggered:

final EventLoop eventloop = f.channel().eventLoop();
b.connect().addListener((ChannelFuture f) -> {
    if (!f.isSuccess()) {
        long nextRetryDelay = nextRetryDelay(...);
        eventloop.schedule(() -> {
            doConnect();
            eventloop.shutdownGracefully();
        }, nextRetryDelay, ...);
    }
});
like image 1
MSillence Avatar answered Nov 10 '22 05:11

MSillence