사내에서 APNs 관련 Retry 로직을 작성하기 위해 학습한 Exponential Backoff 관련 내용을 정리한다.
fallback
처리하는 것은 몇번 재시도하는 것보다 큰 리소스 낭비가 될 수 있다.timeout
의 경우에는 충분히 재시도 해볼만하다고 할 수 있다.timeout
상황의 경우에도 특정 시간동안 네트워크 이슈가 지속되는 경우가 많기 때문에 이를 즉시 재시도한다고해도 모두 실패로 끝날 가능성이 높다.int interval = Math.min(MAX_INTERVAL_TIME, base * Math.pow(2, attempt));
int jitter = Random.nextInt(MIN_JITTER_VALUE, MAX_JITTER_VALUE);
Thread.sleep(inteval + jitter);
ofExponentialRandomBackoff()
라는 형태로 이를 지원하고 있다.static IntervalFunction ofExponentialRandomBackoff(
long initialIntervalMillis,
double multiplier,
double randomizationFactor
) {
checkInterval(initialIntervalMillis);
checkMultiplier(multiplier);
checkRandomizationFactor(randomizationFactor);
return attempt -> {
checkAttempt(attempt);
final long interval =
of(initialIntervalMillis, x -> (long) (x * multiplier))
.apply(attempt);
return (long) randomize(interval, randomizationFactor);
};
}
static double randomize(final double current, final double randomizationFactor) {
final double delta = randomizationFactor * current;
final double min = current - delta;
final double max = current + delta;
return (min + (Math.random() * (max - min + 1)));
}
public void runWithRetry(Runnable runnable) {
runWithRetry(runnable, 0);
}
private void runWithRetry(Runnable runnable, int count) {
try {
runnable.run();
} catch (Exception e) {
if (count >= MAX_RETRY_COUNT) {
throw e;
}
try {
Thread.sleep(BASE_INTERVAL_TIME * Math.pow(2, count) + ThreadLocalRandom.current().nextInt(MIN_JITTER_VALUE, MAX_JITTER_VALUE));
} catch(InterrupedException e) {
}
runWithRetry(runnable, count + 1);
}
}
참고