All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.dongliu.prettypb.rpc.client.RpcClientConnectionWatchdog Maven / Gradle / Ivy

There is a newer version: 0.3.5
Show newest version
/**
 *   Copyright 2010-2014 Peter Klauser
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
package net.dongliu.prettypb.rpc.client;

import io.netty.bootstrap.Bootstrap;
import net.dongliu.prettypb.rpc.RpcClient;
import net.dongliu.prettypb.rpc.info.PeerInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;


/**
 * The idea is for someone to try to keep a connection alive
 *
 * @author Peter Klauser
 */
public class RpcClientConnectionWatchdog {

    private static Logger log = LoggerFactory.getLogger(RpcClientConnectionWatchdog.class);

    private final List watchedClients = new ArrayList<>();

    private final RpcClient rpcClient;
    private final Bootstrap bootstrap;

    private Thread watchdogThread;
    private WatchdogWorker watchdogWorker;
    private long retryInterval = TimeUnit.SECONDS.toMillis(10);

    public RpcClientConnectionWatchdog(RpcClient rpcClient, Bootstrap bootstrap) {
        this.rpcClient = rpcClient;
        this.bootstrap = bootstrap;
    }

    /**
     * start watchdog thread
     */
    public void start() {
        watchdogWorker = new WatchdogWorker(this);
        watchdogThread = new Thread(watchdogWorker);
        watchdogThread.setDaemon(true);
        watchdogThread.start();
    }

    /**
     * stop watchdog thread
     */
    public void stop() {
        if (watchdogWorker != null) {
            watchdogWorker.finish();
            watchdogWorker = null;
        }
        if (watchdogThread != null) {
            watchdogThread = null;
        }
    }

    private boolean retryableNow(RetryState state) {
        if (state.lastRetried == 0) {
            return true;
        }
        if (state.lastRetried + getRetryInterval() <= System.currentTimeMillis()) {
            return true;
        }
        return false;
    }

    private List getRetryableStates() {
        List retryList = new ArrayList<>();
        synchronized (watchedClients) {
            for (RetryState state : watchedClients) {
                if (retryableNow(state)) {
                    retryList.add(state);
                }
            }
        }
        return retryList;
    }

    private void addRetryState(RetryState state) {
        synchronized (watchedClients) {
            watchedClients.add(state);
        }
    }

    private void removeRetryState(RetryState state) {
        synchronized (watchedClients) {
            watchedClients.remove(state);
        }
    }

    private void trigger() {
        WatchdogWorker wt = watchdogWorker;
        if (wt != null) {
            wt.trigger();
        }
    }

    /**
     * @return the retryInterval
     */
    public long getRetryInterval() {
        return retryInterval;
    }

    /**
     * @param retryInterval the retryInterval to set
     */
    public void setRetryInterval(long retryInterval) {
        this.retryInterval = retryInterval;
    }

    /**
     * @return the rpcClient
     */
    public RpcClient getRpcClient() {
        return rpcClient;
    }

    /**
     * @return the bootstrap
     */
    public Bootstrap getBootstrap() {
        return bootstrap;
    }

    private static class RetryState {
        long lastRetried = 0;
        RpcClientChannel rpcClientChannel = null;

        public RetryState(RpcClientChannel clientChannel) {
            rpcClientChannel = clientChannel;
        }

    }

    public static class WatchdogWorker implements Runnable {

        private volatile boolean stopped = false;
        private RpcClientConnectionWatchdog watchdog;
        private final Object triggerSyncObject = new Object();

        public WatchdogWorker(RpcClientConnectionWatchdog watchdog) {
            this.watchdog = watchdog;
        }

        @Override
        public void run() {
            while (!stopped) {
                do {
                    List retryableStates = watchdog.getRetryableStates();
                    if (retryableStates.size() == 0) {
                        // if we've got nothing to do we just wait for a bit before checking again.
                        // if something comes in ( ie. connectionLost ) then start retrying immediately.
                        try {
                            synchronized (triggerSyncObject) {
                                triggerSyncObject.wait(watchdog.getRetryInterval());
                            }
                        } catch (InterruptedException e) {

                        }
                    } else {
                        for (RetryState state : retryableStates) {
                            doRetry(state);
                        }
                    }
                } while (!stopped);
            }
        }

        public void finish() {
            this.stopped = true;
            trigger();
        }

        public void trigger() {
            synchronized (triggerSyncObject) {
                triggerSyncObject.notifyAll();
            }
        }

        void doRetry(RetryState state) {
            RpcClientChannel disconnectedClient = state.rpcClientChannel;

            PeerInfo serverInfo = disconnectedClient.getServerPeer();

            state.lastRetried = System.currentTimeMillis();
            try {
                log.info("Retry connecting " + serverInfo);
                watchdog.getRpcClient().connect();
                log.info("Retry succeeded " + serverInfo);
                watchdog.removeRetryState(state);
            } catch (IOException | TimeoutException e) {
                // leave it in the list
                log.info("Retry failed " + serverInfo, e);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy