Skip to content

Retry Policies ​

Network requests fail. Servers time out. Connections drop. Reacton provides a RetryPolicy class that adds configurable retry behavior with exponential backoff to any async or query reacton.

RetryPolicy ​

The RetryPolicy class controls how failed operations are retried.

dart
const RetryPolicy({
  int maxAttempts = 3,
  Duration initialDelay = const Duration(seconds: 1),
  double backoffMultiplier = 2.0,
  Duration? maxDelay,
  bool Function(Object error)? shouldRetry,
});
PropertyTypeDefaultDescription
maxAttemptsint3Maximum number of retry attempts. The total number of tries is maxAttempts (initial + retries).
initialDelayDuration1 secondDelay before the first retry.
backoffMultiplierdouble2.0Multiplier applied to the delay after each retry (exponential backoff).
maxDelayDuration?nullUpper bound on the delay between retries. Prevents delays from growing unbounded.
shouldRetrybool Function(Object)?nullPredicate that determines if a specific error should be retried. If null, all errors are retried. Return false to fail immediately.

How Backoff Works ​

The delay before retry attempt n (0-indexed) is calculated as:

delay(n) = min(initialDelay * backoffMultiplier^n, maxDelay)

For the default configuration (initialDelay: 1s, backoffMultiplier: 2.0):

AttemptDelay
0 (initial)--
1 (first retry)1 second
2 (second retry)2 seconds
3 (third retry)4 seconds
48 seconds
516 seconds

With maxDelay: Duration(seconds: 10):

AttemptDelay
11 second
22 seconds
34 seconds
48 seconds
510 seconds (capped)

Methods ​

delayForAttempt() ​

Calculate the delay for a given attempt number (0-indexed).

dart
final policy = RetryPolicy(
  initialDelay: Duration(seconds: 1),
  backoffMultiplier: 2.0,
);

print(policy.delayForAttempt(0)); // 1s
print(policy.delayForAttempt(1)); // 2s
print(policy.delayForAttempt(2)); // 4s

canRetry() ​

Check whether a given error should be retried at a given attempt number.

dart
final policy = RetryPolicy(
  maxAttempts: 3,
  shouldRetry: (e) => e is NetworkException,
);

print(policy.canRetry(NetworkException(), 0)); // true
print(policy.canRetry(NetworkException(), 3)); // false (max attempts)
print(policy.canRetry(AuthException(), 0));    // false (not retryable)

Usage with asyncReacton ​

dart
final dataReacton = asyncReacton<Data>(
  (read) => api.fetchData(),
  name: 'data',
  retryPolicy: RetryPolicy(
    maxAttempts: 3,
    initialDelay: Duration(seconds: 1),
    shouldRetry: (e) => e is NetworkException,
  ),
);

Usage with reactonQuery ​

dart
final usersQuery = reactonQuery<List<User>>(
  queryFn: (_) => api.fetchUsers(),
  config: QueryConfig(
    staleTime: Duration(minutes: 5),
    retryPolicy: RetryPolicy(
      maxAttempts: 3,
      initialDelay: Duration(milliseconds: 500),
      backoffMultiplier: 2.0,
      maxDelay: Duration(seconds: 30),
    ),
  ),
  name: 'users',
);

Common Patterns ​

Retry Only Network Errors ​

dart
RetryPolicy(
  maxAttempts: 3,
  shouldRetry: (e) => e is SocketException || e is TimeoutException,
)

No Retry for Client Errors ​

dart
RetryPolicy(
  maxAttempts: 3,
  shouldRetry: (e) {
    if (e is HttpException) {
      // Don't retry 4xx errors (client mistakes)
      return e.statusCode >= 500;
    }
    return true; // retry everything else
  },
)

Fixed Delay (No Backoff) ​

Set backoffMultiplier to 1.0 for a constant delay between retries:

dart
RetryPolicy(
  maxAttempts: 5,
  initialDelay: Duration(seconds: 2),
  backoffMultiplier: 1.0,  // 2s, 2s, 2s, 2s, 2s
)

Aggressive Backoff with Cap ​

dart
RetryPolicy(
  maxAttempts: 10,
  initialDelay: Duration(milliseconds: 100),
  backoffMultiplier: 3.0,
  maxDelay: Duration(seconds: 60),  // never wait more than 1 minute
)

WARNING

Be careful with high maxAttempts and no maxDelay. Exponential backoff grows fast: with a multiplier of 2.0, attempt 10 waits over 17 minutes.

What's Next ​

Released under the MIT License.