This library is useful when you want a retry operation using Exponential backoff algorithm.
Exponential backoff is an algorithm that uses feedback to multiplicatively decrease the rate of some process, in order to gradually find an acceptable rate. In a variety of computer networks, binary exponential backoff or truncated binary exponential backoff refers to an algorithm used to space out repeated retransmissions of the same block of data, often as part of network congestion avoidance.
implementation 'com.yuki312:backoff-core:<latest version>'
If you want to implement a backoff interval with retryWhen of RxJava 2, use the following package:
implementation 'com.yuki312:backoff-rxjava2:<latest version>'
RxBackoff
can be used for error handling using retryWhen
function.
The following code delays the retry process with the Binary Exponential Backoff algorithm.
// retry -> (wait 0.5s) -> retry -> (wait 1s) -> retry -> (wait 2s) -> ...
retrofit.webapi()
.retryWhen(RxBackoff.exponential(2.0 /* Multiplier */ , 5 /* maxRetryCount */).observable())
.subscribe(...)
The following code is a random interval algorithm(not backoff).
// retry -> (wait 1~5000ms) -> retry -> (wait 1~5000ms) -> retry ...
retrofit.webapi()
.retryWhen(RxBackoff.random(1 /* low */, 5000 /* high */, 5 /* maxRetryCount */).observable())
.subscribe(...)
The backoff algorithm allows you to choose the built-in one or choose your own one.
Fine options can also be specified:
RxBackoff(Backoff.Builder()
.setAlgorithm(ExponentialAlgorithm(
5000 /* interval */,
1.5 /* multiplier */,
15_000L /* maxInterval */,
1.2 /* range */))
.setMaxElapsedTime(3, TimeUnit.MINUTES)
.setMaxRetryCount(5)
.build())
.filter { it is HttpException } // You can filtered 500 or 504 here
.doOnRetry { e, cnt -> println("Retry $cnt times, error=$e") }
.doOnAbort { e -> println("Abort, error=$e") })
You can choose to set the Backoff interval to a specific value or a random value from a specific range. For HTTP request retry processing, a random interval is recommended to avoid congestion due to retries. For local retries, random intervals may not be necessary.
multiplier = 1.5 | 1st retry | 2nd retry | 3rd retry |
---|---|---|---|
Interval | 500 (400..600) | 1000 (600..900) | 1500 (900..1350) |
com.yuki312.rxbackoff.ExponentialAlgorithm
// the default interval
public static final long DEFAULT_INTERVAL = 500L;
// the default multiplier (increases the interval by 50%)
public static final double DEFAULT_MULTIPLIER = 1.5;
// the default maximum interval. Truncate time that exceeds 15 seconds.
public static final long DEFAULT_MAX_INTERVAL = 15_000L;
// the default random range. choose randomly within the range of ± 20% of the interval value.
public static final double DEFAULT_RANGE = 0.2;
public ExponentialAlgorithm(long interval, double multiplier, long maxInterval, double range)
multiplier = 2.0 | 1st retry | 2nd retry | 3rd retry |
---|---|---|---|
Interval | 500 (400..600) | 1000 (800..1200) | 2000 (1600..2400) |
com.yuki312.rxbackoff.BinaryExponentialAlgorithm
// multiplier is fixed 2.0
public BinaryExponentialAlgorithm(long interval, long maxInterval, double range)
hMultiplier = 3.0 | 1st retry | 2nd retry | 3rd retry |
---|---|---|---|
Interval | (500..1000) | (500..3000) | (500..9000) |
com.yuki312.rxbackoff.RandomIntervalAlgorithm
// the default lower interval
public static final long DEFAULT_LOW_INTERVAL = 500L;
// the default high interval
public static final long DEFAULT_HIGH_INTERVAL = 1000L;
// the default multiplier (no increases the interval)
public static final double DEFAULT_LOW_MULTIPLIER = 1.0;
// the default multiplier (no increases the interval)
public static final double DEFAULT_HIGH_MULTIPLIER = 3.0;
// the default maximum interval. Truncate time that exceeds 15 seconds.
public static final long DEFAULT_MAX_INTERVAL = 15_000L;
public RandomIntervalAlgorithm(long lowInterval, long highInterval,
double lowMultiplier, double highMultiplier,
long maxInterval)
multiplier = 0.0 | 1st retry | 2nd retry | 3rd retry |
---|---|---|---|
Interval | 500 | 500 | 500 |
This algorithm is not backed off.
com.yuki312.rxbackoff.FixedIntervalAlgorithm
// the default interval
public static final long DEFAULT_INTERVAL = 500L;
public FixedIntervalAlgorithm(long interval, TimeUnit unit)
You can also use your own backoff algorithm. If Backoff.ABORT(0)
is returned, backoff processing will be aborted.
RxBackoff.of({ retry, elapsed ->
2F.pow(retry - 1).toLong().times(1000L).coerceAtMost(5000L)
}, 5)
The 'truncated' simply means that after a certain number of increases, the exponentiation stops; i.e. the retransmission timeout reaches a ceiling and thereafter does not increase any further. All built-in algorithms support Truncated.
// the default maximum interval. Truncate time that exceeds 15 seconds.
public static final long DEFAULT_MAX_INTERVAL = 15_000L;
/**
* @param maxInterval the maximum interval. Truncate time that exceeds
**/
public BinaryExponentialAlgorithm(long interval, long maxInterval)
You can abort retry processing when certain conditions are satisfied. RxBackoff measures the number of retry processes and elapsed time. When retry count or elapsed time exceeds the threshold value, the retry process is aborted.
com.yuki312.rxbackoff.Backoff.Builder
public Builder setMaxRetryCount(int count) {...}
public Builder setMaxElapsedTime(long elapsedTime, TimeUnit unit)
Function | Description |
---|---|
exponential | Use Binary exponential backoff algorithm |
fixed | Use Fixed interval algorithm |
of | Retry specified number of times with specified algorithm |
filter | Filters errors emitted by an ObservableSource |
doOnRetry | Callback function called every time before retry processing |
doOnAbort | Callback function called when giving up retry |
retrofit.webapi()
.retryWhen(
RxBackoff.exponential(maxRetryCount = 5)
.filter { it is HttpException } // You can filtered 500 or 504 here
.doOnRetry { e, cnt -> println("Retry $cnt times, error=$e") }
.doOnAbort { e -> println("Abort, error=$e") }
.observable())
Copyright 2017 Matsumura Yuki. Licensed under the Apache License, Version 2.0;