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

后端 未结 3 1601
青春惊慌失措
青春惊慌失措 2021-02-01 10:11

Simple scenario:

  1. A lower level class A that extends SimpleChannelUpstreamHandler. This class is the workhorse to send the message and received the response.
3条回答
  •  一生所求
    2021-02-01 11:15

    Here's another version encapsulating the reconnect behavior in a small helper class

    Bootstrap clientBootstrap...
    EventLoopGroup group = new NioEventLoopGroup();
    
    Session session = new Session(clientBootstrap,group);
    Disposable shutdownHook = session.start();    
    
    interface Disposable {
       void dispose();
    }
    class Session implements Disposable{    
        private final EventLoopGroup scheduler;
        private final Bootstrap clientBootstrap;
    
        private int reconnectDelayMs;
        private Channel activeChannel;
        private AtomicBoolean shouldReconnect;
    
        private Session(Bootstrap clientBootstrap, EventLoopGroup scheduler) {
            this.scheduler = scheduler;
            this.clientBootstrap = clientBootstrap;
            this.reconnectDelayMs = 1;
            this.shouldReconnect = new AtomicBoolean(true);
        }
    
        public Disposable start(){
            //Create a new connectFuture
            ChannelFuture connectFuture = clientBootstrap.connect();
    
            connectFuture.addListeners( (ChannelFuture cf)->{
                if(cf.isSuccess()){
                    L.info("Connection established");
                    reconnectDelayMs =1;                    
                    activeChannel = cf.channel();
    
                    //Listen to the channel closing
                    var closeFuture =activeChannel.closeFuture();
                    closeFuture.addListeners( (ChannelFuture closeFut)->{
                        if(shouldReconnect.get()) {
                            activeChannel.eventLoop().schedule(this::start, nextReconnectDelay(), TimeUnit.MILLISECONDS);
                        }
                        else{
                            L.info("Session has been disposed won't reconnect");
                        }
                    });
                }
                else{
                    int delay =nextReconnectDelay();
                    L.info("Connection failed will re-attempt in {} ms",delay);
                    cf.channel().eventLoop().schedule(this::start,delay , TimeUnit.MILLISECONDS);
                }
            });
            
            return this;
        }
    
        /**
         * Call this to end the session
         */
        @Override
        public void dispose() {
            try {
                shouldReconnect.set(false);
                scheduler.shutdownGracefully().sync();
                if(activeChannel !=null) {
                    activeChannel.closeFuture().sync();
                }
            }catch(InterruptedException e){
                L.warn("Interrupted while shutting down TcpClient");
            }
        }
    
        private int nextReconnectDelay(){
            this.reconnectDelayMs = this.reconnectDelayMs*2;
            return Math.min(this.reconnectDelayMs, 5000);
        }
    }
    

提交回复
热议问题