run<T> static method

Future<T> run<T>(
  1. FutureOr<T> callback(), {
  2. CancelToken? cancel,
  3. bool retryIf(
    1. Object e
    ) = _defaultRetryIf,
  4. int retries = 0,
})

Returns result of the provided callback using the exponential backoff algorithm on any errors.

retries specified to 0 means infinite retrying.

Implementation

static Future<T> run<T>(
  FutureOr<T> Function() callback, {
  CancelToken? cancel,
  bool Function(Object e) retryIf = _defaultRetryIf,
  int retries = 0,
}) async {
  int index = 0;

  final CancelableOperation operation = CancelableOperation.fromFuture(
    Future(() async {
      Duration backoff = Duration.zero;

      while (true) {
        await Future.delayed(backoff);
        if (cancel?.isCancelled == true) {
          throw OperationCanceledException();
        }

        try {
          return await callback();
        } catch (e, _) {
          if (!retryIf(e)) {
            rethrow;
          }

          ++index;
          if (retries > 0 && index >= retries) {
            rethrow;
          }

          if (backoff.inMilliseconds == 0) {
            backoff = _minBackoff;
          } else if (backoff < _maxBackoff) {
            backoff *= 2;
          }

          Log.debug(e.toString(), 'Backoff');
        }
      }
    }),
  );

  cancel?.whenCancel.then((_) => operation.cancel());

  final result = await operation.valueOrCancellation();
  if (operation.isCanceled) {
    throw OperationCanceledException();
  }

  return result;
}