66 lines
1.9 KiB
Dart
66 lines
1.9 KiB
Dart
// 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();
|
|
|
|
/// Determines if [value] is acceptable. For good style an implementation should
|
|
/// be idempotent.
|
|
typedef bool Predicate(dynamic value);
|
|
|
|
/// 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].
|
|
Future<dynamic> retry(Action action, Duration timeout,
|
|
Duration pauseBetweenRetries, { Predicate predicate }) async {
|
|
assert(action != null);
|
|
assert(timeout != null);
|
|
assert(pauseBetweenRetries != null);
|
|
|
|
final Stopwatch sw = stopwatchFactory()..start();
|
|
dynamic result;
|
|
dynamic lastError;
|
|
dynamic lastStackTrace;
|
|
bool success = false;
|
|
|
|
while(!success && sw.elapsed < timeout) {
|
|
try {
|
|
result = await action();
|
|
if (predicate == null || predicate(result))
|
|
success = true;
|
|
lastError = null;
|
|
lastStackTrace = null;
|
|
} catch(error, stackTrace) {
|
|
lastError = error;
|
|
lastStackTrace = stackTrace;
|
|
}
|
|
|
|
if (!success && sw.elapsed < timeout)
|
|
await new Future<Null>.delayed(pauseBetweenRetries);
|
|
}
|
|
|
|
if (success)
|
|
return result;
|
|
else if (lastError != null)
|
|
return new Future<Null>.error(lastError, lastStackTrace);
|
|
else
|
|
return new Future<Null>.error('Retry timed out');
|
|
}
|
|
|
|
/// 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();
|