| # Copyright 2020 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| """Helper functions for common boilerplate tasks. |
| |
| Top-level functions stored in __init__.py can be imported and used directly |
| (without needing a `RecipeApi` object) using `RECIPE_MODULES` imports. E.g.: |
| |
| ``` |
| from RECIPE_MODULES.fuchsia.utils import memoize |
| |
| @memoize |
| def expensive_computation(inputs): |
| return do_work(inputs) |
| |
| def RunSteps(api, ...): |
| expensive_computation(...) |
| ``` |
| """ |
| |
| from recipe_engine import recipe_api |
| |
| |
| class UtilsApi(recipe_api.RecipeApi): |
| def retry(self, func, max_attempts, sleep=5.0, backoff_factor=1.5): |
| """Retry the given function with exponential backoff. |
| |
| Args: |
| func (callable): A function that performs the action that should |
| be retried on failure. If it raises a `StepFailure` it will |
| be retried. Any other exception will end the retry loop and |
| bubble up. |
| max_attempts (int): How many times to try before giving up. |
| sleep (int or float): The time to sleep after the first attempt. |
| backoff_factor (int or float): The factor by which the sleep time |
| will be multiplied after each attempt. |
| """ |
| for attempt in range(max_attempts): |
| try: |
| return func() |
| except self.m.step.StepFailure: |
| if attempt == max_attempts - 1: |
| raise |
| |
| self.m.time.sleep(sleep) |
| sleep *= backoff_factor |