asyncRetry<R> function

FutureOr<R?> asyncRetry<R>(
  1. FutureOr<R?> tryBlock(), {
  2. R? defaultValue,
  3. bool throwOnRetryExhaustion = false,
  4. int maxRetries = 3,
  5. Duration? retryDelay,
  6. Duration? computeDelay(
    1. int retry
    )?,
  7. bool? onError(
    1. Object error,
    2. StackTrace stackTrace,
    3. int retries
    )?,
})

Executes an asynchronous operation with retry logic.

Retries the tryBlock function up to maxRetries times if it throws an error, with customizable delay and error handling.

Parameters:

  • tryBlock: The operation to execute. Retries if it throws an error.
  • defaultValue: Value to return if retries are exhausted and throwOnRetryExhaustion is false. Defaults to null.
  • throwOnRetryExhaustion: If true, rethrows the last error when retries are exhausted. Defaults to false, which returns defaultValue instead.
  • maxRetries: Maximum number of retry attempts. Defaults to 3.
  • retryDelay: Fixed delay between retries. Defaults to 1ms. Overridden by computeDelay if provided.
  • computeDelay: Computes a custom delay for each retry based on the retry count.
  • onError: Callback to handle errors during retries. Receives:
    • error: The exception thrown by tryBlock.
    • stackTrace: The stack trace associated with the error.
    • retries: The number of retry attempts already made (starting at 0). If onError returns false, stops retrying immediately.

Returns:

A FutureOr<R?> with the result of tryBlock if successful. If retries are exhausted:

  • Returns defaultValue if throwOnRetryExhaustion is false.
  • Rethrows the last error if throwOnRetryExhaustion is true.

Example:

// Some network request:
Future<String?> fetchData() async {
  throw Exception('Network error');
}

Future<void> main() async {
  var result = await asyncRetry<String?>(
    () => fetchData(),
    defaultValue: 'Fallback value',  // Return this if retries are exhausted and throwOnRetryExhaustion is false.
    maxRetries: 5,                   // Retry up to 5 times before giving up.
    retryDelay: Duration(seconds: 2), // 2 seconds delay between retries.
    throwOnRetryExhaustion: true,     // Rethrow the last error if all retries fail.
    onError: (error, stackTrace, retries) {
      print('Attempt failed (retries: $retries): $error');
      return null; // Continue retrying based on maxRetries without modifying retry behavior.
      // If returns `false`, retries stop early.
      // If returns `true`, retries continue even if maxRetries is exceeded.
    },
  );

  print('Result: $result');
}

Notes:

  • If throwOnRetryExhaustion is true and retries fail, the last error will be rethrown.
  • If computeDelay is provided, it overrides retryDelay.
  • The onError callback can stop retries early by returning false.

Throws:

  • The last error from tryBlock if retries are exhausted and throwOnRetryExhaustion is true.

Implementation

FutureOr<R?> asyncRetry<R>(FutureOr<R?> Function() tryBlock,
    {R? defaultValue,
    bool throwOnRetryExhaustion = false,
    int maxRetries = 3,
    Duration? retryDelay,
    Duration? Function(int retry)? computeDelay,
    bool? Function(Object error, StackTrace stackTrace, int retries)?
        onError}) {
  if (maxRetries < 0) {
    maxRetries = 0;
  }

  retryDelay ??= Duration(milliseconds: 1);

  return _asyncRetryImpl(tryBlock, 0, maxRetries, defaultValue,
      throwOnRetryExhaustion, retryDelay, computeDelay, onError);
}