retry<T> method

Future<T> retry<T>(
  1. FutureOr<T> fn(), {
  2. FutureOr<bool> retryIf(
    1. Exception
    )?,
  3. FutureOr<void> onRetry(
    1. Exception
    )?,
})

Implementation

Future<T> retry<T>(
  FutureOr<T> Function() fn, {
  FutureOr<bool> Function(Exception)? retryIf,
  FutureOr<void> Function(Exception)? onRetry,
}) async {
  final deadline = DateTime.now().add(maxTime);
  var attempt = 0;
  while (true) {
    attempt++;
    try {
      return await fn();
    } on Exception catch (e) {
      int? retryAfter = -1;
      if (e is InfluxDBException) {
        retryAfter = e.retryAfter;
      }

      // Bail out immediately if not retryable
      if (retryIf != null && !(await retryIf(e))) {
        rethrow;
      }

      // Bail out when max number of retries was reached (first attempt is not counted as a retry)
      if (attempt >= maxRetries + 1) {
        throw RetryException('Maximum retry attempts reached', e);
      }

      // Bail out when max retry time is exceeded
      if (DateTime.now().isAfter(deadline)) {
        throw RetryException(
            'Maximum retry time (${maxTime.inMilliseconds}ms) exceeded', e);
      }

      // Execute handler if any
      if (onRetry != null) {
        await onRetry(e);
      }

      // Sleep for suggested delay but respect timeout
      final duration = delay(attempt, retryAfter, deadline);
      logPrint('The retryable error occurred during request. '
          'Reason: $e Attempt: $attempt '
          'Next retry in: ${duration.inSeconds}s. (${duration.toString()})');
      await Future.delayed(duration);
    }
  }
}