| // 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(); |
| |
| /// 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) async { |
| assert(action != null); |
| assert(timeout != null); |
| assert(pauseBetweenRetries != null); |
| |
| Stopwatch sw = stopwatchFactory()..start(); |
| dynamic result = null; |
| dynamic lastError = null; |
| dynamic lastStackTrace = null; |
| bool success = false; |
| |
| while(!success && sw.elapsed < timeout) { |
| try { |
| result = await action(); |
| success = true; |
| } catch(error, stackTrace) { |
| lastError = error; |
| lastStackTrace = stackTrace; |
| if (sw.elapsed < timeout) { |
| await new Future<Null>.delayed(pauseBetweenRetries); |
| } |
| } |
| } |
| |
| if (success) |
| return result; |
| else |
| return new Future.error(lastError, lastStackTrace); |
| } |
| |
| /// 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(); |