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

io.hekate.messaging.retry.ExponentialBackoffPolicy Maven / Gradle / Ivy

/*
 * Copyright 2022 The Hekate Project
 *
 * The Hekate Project licenses this file to you 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 io.hekate.messaging.retry;

import io.hekate.core.internal.util.ArgAssert;
import io.hekate.util.format.ToString;
import io.hekate.util.format.ToStringIgnore;

/**
 * A backoff policy that waits exponentially longer between each attempt (but keeps a constant delay once a maximum delay is reached).
 *
 * 

* This policy uses the following formula to calculate the backoff delay: *

* *
{@code
 *   (2 ^ (attempt -1)) * baseDelay
 * }
* *

* Note: for the very first attempt the answer is always {@code 0} (i.e. retry immediately). *

* *

* Parameters of this policy are: *

* *
    *
  • {@code BaseDelay} - multiplier for each attempt
  • *
  • {@code MaxDelay} - maximum delay (calculated delay will never exceed this value)
  • *
* *

* Examples of calculations: *

* *
{@code
 * BaseDelay: 10  MaxDelay: 3000
 * -------------------------------
 *  Attempt 0  -> 0
 *  Attempt 1  -> 10
 *  Attempt 2  -> 20
 *  Attempt 3  -> 40
 *  Attempt 4  -> 80
 *  Attempt 5  -> 160
 *  Attempt 6  -> 320
 *  Attempt 7  -> 640
 *  Attempt 8  -> 1280
 *  Attempt 9  -> 2560
 *  Attempt 10 -> 3000
 *  ...        -> 3000
 * }
*
{@code
 * BaseDelay: 500  MaxDelay: 30000
 * -------------------------------
 *  Attempt 0 -> 0
 *  Attempt 1 -> 500
 *  Attempt 2 -> 1000
 *  Attempt 3 -> 2000
 *  Attempt 4 -> 4000
 *  Attempt 5 -> 8000
 *  Attempt 6 -> 16000
 *  Attempt 7 -> 30000
 *  ...       -> 30000
 * }
*/ public class ExponentialBackoffPolicy implements RetryBackoffPolicy { /** Default base delay (={@value}) in milliseconds. */ public static final long DEFAULT_BASE_DELAY = 50; /** Default maximum delay (={@value}) in milliseconds. */ public static final long DEFAULT_MAX_DELAY = 3000; /** Base delay. */ private final long baseDelay; /** Maximum delay. */ private final long maxDelay; /** Max attempt limit (max value before calculations overflow). */ @ToStringIgnore private final int attemptOverflow; /** * Constructs a new instance with default values. * * @see #DEFAULT_BASE_DELAY * @see #DEFAULT_MAX_DELAY */ public ExponentialBackoffPolicy() { this(DEFAULT_BASE_DELAY, DEFAULT_MAX_DELAY); } /** * Constructs a new instance. * * @param baseDelay Multiplier for each attempt (in milliseconds). * @param maxDelay Maximum delay in milliseconds (calculated delay will never exceed this value). */ public ExponentialBackoffPolicy(long baseDelay, long maxDelay) { ArgAssert.positive(baseDelay, "Base delay"); ArgAssert.positive(maxDelay, "Maximum delay"); ArgAssert.check(baseDelay <= maxDelay, "Base delay can't be less than max delay."); this.baseDelay = baseDelay; this.maxDelay = maxDelay; // Maximum attempts before we start to overflow. this.attemptOverflow = Long.SIZE - Long.numberOfLeadingZeros(Long.MAX_VALUE / baseDelay) - 1; } /** * Returns the base delay of this policy in milliseconds. * * @return Base delay in milliseconds. */ public long baseDelay() { return baseDelay; } /** * Returns the maximum delay of this policy in milliseconds. * * @return Maximum delay in milliseconds. */ public long maxDelay() { return maxDelay; } @Override public long delayBeforeRetry(int attempt) { if (attempt == 0) { return 0; } else if (attempt >= attemptOverflow) { return maxDelay; } else { int calcAttempt = attempt - 1; // <- First attempt must be always retried immediately. return (long)Math.min(Math.pow(2, calcAttempt) * baseDelay, maxDelay); } } @Override public String toString() { return ToString.format(this); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy