| // 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); |
| |
| 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.error(lastError, lastStackTrace); |
| else |
| return new Future.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(); |