Backoff is a strategy for dealing with failures, conflicts, or resource competition.
The core logic is: when an operation fails or encounters a limitation, it will pause for a period of time before trying again, and the retry interval is usually adjusted dynamically to avoid increasing system pressure or conflicts.
let’s see how spring-framework implement it.
BackOff Strategy interface for providing a BackOffExecution that indicates the rate at which an operation should be retried.
1 2 3 4 5 6 @FunctionalInterface public interface BackOff { BackOffExecution start () ; }
BackOffExecution An executable instance of a given BackOff strategy.
1 2 3 4 5 6 7 8 9 @FunctionalInterface public interface BackOffExecution { long STOP = -1 ; long nextBackOff () ; }
FixedBackOff Provides a fixed interval between two attempts and a maximum number of retries.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public class FixedBackOff implements BackOff { public static final long DEFAULT_INTERVAL = 5000 ; public static final long UNLIMITED_ATTEMPTS = Long.MAX_VALUE; private long interval = DEFAULT_INTERVAL; private long maxAttempts = UNLIMITED_ATTEMPTS; @Override public BackOffExecution start () { return new FixedBackOffExecution (); } private class FixedBackOffExecution implements BackOffExecution { private long currentAttempts = 0 ; @Override public long nextBackOff () { this .currentAttempts++; if (this .currentAttempts <= getMaxAttempts()) { return getInterval(); } else { return STOP; } } } }
ExponentialBackOff Increases the back-off period for each attempt.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 public class ExponentialBackOff implements BackOff { public static final long DEFAULT_INITIAL_INTERVAL = 2000L ; public static final long DEFAULT_JITTER = 0 ; public static final double DEFAULT_MULTIPLIER = 1.5 ; public static final long DEFAULT_MAX_INTERVAL = 30_000L ; public static final long DEFAULT_MAX_ELAPSED_TIME = Long.MAX_VALUE; public static final long DEFAULT_MAX_ATTEMPTS = Long.MAX_VALUE; private long initialInterval = DEFAULT_INITIAL_INTERVAL; private long jitter = DEFAULT_JITTER; private double multiplier = DEFAULT_MULTIPLIER; private long maxInterval = DEFAULT_MAX_INTERVAL; private long maxElapsedTime = DEFAULT_MAX_ELAPSED_TIME; private long maxAttempts = DEFAULT_MAX_ATTEMPTS; @Override public BackOffExecution start () { return new ExponentialBackOffExecution (); } private class ExponentialBackOffExecution implements BackOffExecution { private long currentInterval = -1 ; private long currentElapsedTime = 0 ; private int attempts = 0 ; @Override public long nextBackOff () { if (this .currentElapsedTime >= getMaxElapsedTime() || this .attempts >= getMaxAttempts()) { return STOP; } long nextInterval = computeNextInterval(); this .currentElapsedTime += nextInterval; this .attempts++; return nextInterval; } private long computeNextInterval () { long maxInterval = getMaxInterval(); long nextInterval; if (this .currentInterval < 0 ) { nextInterval = getInitialInterval(); } else if (this .currentInterval >= maxInterval) { nextInterval = maxInterval; } else { nextInterval = Math.min((long ) (this .currentInterval * getMultiplier()), maxInterval); } this .currentInterval = nextInterval; return Math.min(applyJitter(nextInterval), maxInterval); } private long applyJitter (long interval) { long jitter = getJitter(); if (jitter > 0 ) { long initialInterval = getInitialInterval(); long applicableJitter = jitter * (interval / initialInterval); long min = Math.max(interval - applicableJitter, initialInterval); long max = Math.min(interval + applicableJitter, getMaxInterval()); return min + (long ) (Math.random() * (max - min)); } return interval; } } }
Usage 1 2 3 4 5 6 7 8 9 10 11 12 13 ExponentialBackOff backOff = new ExponentialBackOff ();BackOffExecution execution = backOff.start();long waitInterval = execution.nextBackOff();if (waitInterval == BackOffExecution.STOP) { } else { }
End.
Title: BackOff
Author: Jiandong
Date: 2025-07-06
Last Update: 2026-06-16
Blog Link: https://mjd507.github.io/2025/07/06/BackOff/
Copyright Declaration: Please refer carefully, most of the content I have not fully mastered.