com.zipwhip.api.signals.reconnect.DefaultReconnectStrategy Maven / Gradle / Ivy
package com.zipwhip.api.signals.reconnect;
import com.zipwhip.api.signals.sockets.ConnectionHandle;
import com.zipwhip.concurrent.ObservableFuture;
import com.zipwhip.events.Observer;
import com.zipwhip.executors.NamedThreadFactory;
import com.zipwhip.reliable.retry.ExponentialBackoffRetryStrategy;
import com.zipwhip.reliable.retry.RetryStrategy;
import com.zipwhip.timers.HashedWheelTimer;
import com.zipwhip.timers.Timeout;
import com.zipwhip.timers.Timer;
import com.zipwhip.timers.TimerTask;
import com.zipwhip.util.FutureDateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.TimeUnit;
/**
* Created by IntelliJ IDEA.
* User: jed
* Date: 9/7/11
* Time: 2:29 PM
*
* Try to reconnect the SignalConnection every 5 seconds until we get a successful connection.
*/
public class DefaultReconnectStrategy extends ReconnectStrategy {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultReconnectStrategy.class);
private ObservableFuture connectFuture;
private Timeout timeout;
private RetryStrategy strategy;
private final Timer timer;
private int failCount;
public DefaultReconnectStrategy() {
this(null);
}
public DefaultReconnectStrategy(Timer timer) {
this(timer, null);
}
public DefaultReconnectStrategy(Timer timer, RetryStrategy strategy) {
super();
if (timer == null) {
timer = new HashedWheelTimer(new NamedThreadFactory(this.toString()), 1, TimeUnit.SECONDS);
}
this.timer = timer;
if (strategy == null) {
strategy = new ExponentialBackoffRetryStrategy(1, 2.0);
}
this.strategy = strategy;
}
@Override
public synchronized void stop() {
cleanup();
// Stop listening to SignalConnection events
super.stop();
}
@Override
protected synchronized void doStrategyWithoutBlocking() {
long delay = getReconnectDelay();
LOGGER.debug(String.format("Scheduling a reconnect attempt to occur on %s", FutureDateUtil.inFuture(delay, TimeUnit.MILLISECONDS)));
timeout = timer.newTimeout(reconnectTimerTask, delay, TimeUnit.MILLISECONDS);
}
private long getReconnectDelay() {
return strategy.getNextRetryInterval(failCount);
}
private final Observer> incrementFailCountOnCompleteObserver = new Observer>() {
@Override
public void notify(Object sender, ObservableFuture future) {
synchronized (DefaultReconnectStrategy.this) {
if (future.isSuccess()) {
failCount = 0;
} else {
failCount++;
}
}
}
};
private TimerTask reconnectTimerTask = new TimerTask() {
@Override
public void run(Timeout timeout) throws Exception {
if (timeout.isCancelled()) {
return; //WARNING: is this the right thing to do?
}
synchronized (DefaultReconnectStrategy.this) {
cancelExistingConnectFuture();
connectFuture = signalConnection.connect();
connectFuture.addObserver(incrementFailCountOnCompleteObserver);
}
}
};
protected synchronized void cleanup() {
cancelExistingConnectFuture();
cancelExistingTimeout();
}
private synchronized void cancelExistingConnectFuture() {
if (connectFuture == null) {
return;
}
// If we have scheduled a reconnect cancel it
if (!connectFuture.isDone()) {
boolean cancelled = connectFuture.cancel(true);
LOGGER.debug("Cancelling reconnect task success: " + cancelled);
}
connectFuture = null;
}
private synchronized void cancelExistingTimeout() {
if (timeout == null) {
return;
}
LOGGER.debug("stop() called, Shutting down scheduled execution");
timeout.cancel();
timeout = null;
}
@Override
protected void onDestroy() {
stop();
}
@Override
public String toString() {
return "DefaultReconnectStrategy";
}
public void setFailCount(int failCount) {
this.failCount = failCount;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy