/*
* Copyright (c) 2015, Jurriaan Mous and contributors as indicated by the @author tags.
*
* 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 mousio.client.retry;
import mousio.client.ConnectionState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;
/**
* Interface for handling a retry
*/
public abstract class RetryPolicy {
private static final Logger logger = LoggerFactory.getLogger(RetryPolicy.class);
protected final int startRetryTime;
/**
* Constructor
*
* @param startRetryTime start milliseconds before trying retry
*/
public RetryPolicy(int startRetryTime) {
this.startRetryTime = startRetryTime;
}
/**
* Does the retry. Will always try all URIs before throwing an exception.
*
* @param state of connection
* @param retryHandler handles the retry itself
* @param failHandler handles the fail
* @throws RetryCancelled if retry is cancelled
*/
public final void retry(final ConnectionState state, final RetryHandler retryHandler, final ConnectionFailHandler failHandler) throws RetryCancelled {
if (state.retryCount == 0) {
state.msBeforeRetry = this.startRetryTime;
}
state.retryCount++;
state.uriIndex = state.retryCount % state.uris.length;
if (this.shouldRetry(state)) {
if (logger.isDebugEnabled()) {
logger.debug("Retry {} to send command", state.retryCount);
}
if(state.msBeforeRetry > 0) {
try {
state.loop.schedule(new Runnable() {
@Override
public void run() {
try {
retryHandler.doRetry(state);
} catch (IOException e) {
failHandler.catchException(e);
}
}
}, state.msBeforeRetry, TimeUnit.MILLISECONDS);
} catch (IllegalStateException e) {
failHandler.catchException(
new IOException(new CancellationException("Etcd client was closed"))
);
}
} else {
try {
retryHandler.doRetry(state);
} catch (IOException e) {
failHandler.catchException(e);
}
}
} else {
throw new RetryCancelled();
}
}
/**
* Cancelled retry exception
*/
public static class RetryCancelled extends Exception {
private static final long serialVersionUID = 8043829471264975062L;
}
/**
* Should another retry be attempted according to the policy
*
* @param connectionState current connection state
* @return true if retry should be attempted, false if not.
*/
public abstract boolean shouldRetry(ConnectionState connectionState);
}