retry.dart 1.94 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';

/// Performs an action and returns either the result of the action or a [Future]
/// that evaluates to the result.
typedef dynamic Action();

11 12 13 14
/// Determines if [value] is acceptable. For good style an implementation should
/// be idempotent.
typedef bool Predicate(dynamic value);

15 16 17 18 19
/// Performs [action] repeatedly until it either succeeds or [timeout] limit is
/// reached.
///
/// When the retry time out, the last seen error and stack trace are returned in
/// an error [Future].
20 21 22 23 24 25
Future<dynamic> retry(
  Action action,
  Duration timeout,
  Duration pauseBetweenRetries, {
  Predicate predicate,
}) async {
26 27 28 29
  assert(action != null);
  assert(timeout != null);
  assert(pauseBetweenRetries != null);

30
  final Stopwatch sw = stopwatchFactory()..start();
Ian Hickson's avatar
Ian Hickson committed
31 32 33
  dynamic result;
  dynamic lastError;
  dynamic lastStackTrace;
34 35
  bool success = false;

36
  while (!success && sw.elapsed < timeout) {
37 38
    try {
      result = await action();
39 40 41 42
      if (predicate == null || predicate(result))
        success = true;
      lastError = null;
      lastStackTrace = null;
43 44 45 46
    } catch(error, stackTrace) {
      lastError = error;
      lastStackTrace = stackTrace;
    }
47 48 49

    if (!success && sw.elapsed < timeout)
      await new Future<Null>.delayed(pauseBetweenRetries);
50 51 52 53
  }

  if (success)
    return result;
54
  else if (lastError != null)
55
    return new Future<Null>.error(lastError, lastStackTrace);
56
  else
57
    return new Future<Null>.error('Retry timed out');
58
}
59 60 61 62 63 64 65 66 67 68 69

/// A function that produces a [Stopwatch].
typedef Stopwatch StopwatchFactory();

/// Restores [stopwatchFactory] to the default implementation.
void restoreStopwatchFactory() {
  stopwatchFactory = () => new Stopwatch();
}

/// Used by [retry] as a source of [Stopwatch] implementation.
StopwatchFactory stopwatchFactory = () => new Stopwatch();