retry<T> function

Future<T> retry<T>(
  1. Future<T> fn(), {
  2. int count = 3,
  3. Duration? delay,
  4. Duration? jitter,
  5. bool condition(
    1. Object error
    )?,
})

Retries fn up to count times with configurable delay and jitter.

If condition is provided, only retries when condition(error) returns true. Otherwise retries on any error.

Matching the TS SDK signature:

export async function retry<T>(
  fn: () => Promise<T>,
  options: { condition?, count?, delay?, jitter? },
): Promise<T>

Example:

final result = await retry(
  () => storageNodeClient.storeBlobMetadata(blobId: id, metadata: meta),
  count: 3,
  delay: const Duration(milliseconds: 1000),
  condition: (e) => e is BlobNotRegisteredError,
);

Implementation

Future<T> retry<T>(
  Future<T> Function() fn, {
  int count = 3,
  Duration? delay,
  Duration? jitter,
  bool Function(Object error)? condition,
}) async {
  int remaining = count;
  final random = jitter != null ? Random() : null;

  while (remaining > 0) {
    try {
      remaining -= 1;
      return await fn();
    } catch (error) {
      if (remaining <= 0 || (condition != null && !condition(error))) {
        rethrow;
      }

      if (delay != null) {
        final jitterMs = jitter != null
            ? (random!.nextDouble() * jitter.inMilliseconds)
            : 0;
        final totalDelay = Duration(
          milliseconds: delay.inMilliseconds + jitterMs.toInt(),
        );
        await Future<void>.delayed(totalDelay);
      }
    }
  }

  // Should never be reached
  throw StateError('Retry count exceeded');
}