com.twitter.hbc.BasicReconnectionManager Maven / Gradle / Ivy
/**
* Copyright 2013 Twitter, Inc.
* 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 com.twitter.hbc;
import com.google.common.annotations.VisibleForTesting;
import com.twitter.hbc.core.Constants;
/**
* This manages all of the reconnection logic. Mostly just keeps a bunch of information about whether we should
* reconnect at all, how much we should backfill, and how much to back off from connection failures.
*/
public class BasicReconnectionManager implements ReconnectionManager {
public static final int INITIAL_EXPONENTIAL_BACKOFF_MILLIS = 5000;
public static final int INITIAL_LINEAR_BACKOFF_MILLIS = 250;
public static final int MAX_LINEAR_BACKOFF_MILLIS = 16000;
public static final int MAX_EXPONENTIAL_BACKOFF_MILLIS = 320000;
private final int maxRetries;
private int currentRetryCount;
private int exponentialBackoffCount;
private int linearBackoffCount;
private int backoffMillis;
public BasicReconnectionManager(int maxRetries) {
this.maxRetries = maxRetries;
}
@Override
public void handleExponentialBackoff() {
handleBackoff(incrAndGetExponentialBackoff());
}
@Override
public void handleLinearBackoff() {
handleBackoff(incrAndGetLinearBackoff());
}
@Override
public boolean shouldReconnectOn400s() {
currentRetryCount++;
return currentRetryCount <= maxRetries;
}
@Override
public int estimateBackfill(double tps) {
return Math.min(Constants.MAX_BACKOFF_COUNT, (int) tps * (backoffMillis));
}
@Override
public void resetCounts() {
linearBackoffCount = 0;
exponentialBackoffCount = 0;
currentRetryCount = 0;
backoffMillis = 0;
}
private void handleBackoff(int millis) {
backoffMillis += millis;
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
// TODO: log an error
}
}
@VisibleForTesting
int incrAndGetExponentialBackoff() {
linearBackoffCount = 0;
exponentialBackoffCount += 1;
return calculateExponentialBackoffMillis();
}
@VisibleForTesting
int incrAndGetLinearBackoff() {
exponentialBackoffCount = 0;
linearBackoffCount += 1;
return calculateLinearBackoffMillis();
}
private int calculateExponentialBackoffMillis() {
assert(exponentialBackoffCount > 0);
return Math.min(MAX_EXPONENTIAL_BACKOFF_MILLIS, INITIAL_EXPONENTIAL_BACKOFF_MILLIS << (exponentialBackoffCount - 1));
}
private int calculateLinearBackoffMillis() {
return Math.min(MAX_LINEAR_BACKOFF_MILLIS, INITIAL_LINEAR_BACKOFF_MILLIS * linearBackoffCount);
}
}