Rob Mohr | 8d13e25 | 2022-09-27 20:01:44 +0000 | [diff] [blame] | 1 | # Copyright 2022 The Pigweed Authors |
| 2 | # |
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| 4 | # use this file except in compliance with the License. You may obtain a copy of |
| 5 | # the License at |
| 6 | # |
| 7 | # https://www.apache.org/licenses/LICENSE-2.0 |
| 8 | # |
| 9 | # Unless required by applicable law or agreed to in writing, software |
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 12 | # License for the specific language governing permissions and limitations under |
| 13 | # the License. |
| 14 | """Ensure the given call completes before swarming kills the build.""" |
| 15 | |
| 16 | import contextlib |
| 17 | import dataclasses |
Rob Mohr | 0b9859a | 2024-03-06 23:25:38 +0000 | [diff] [blame^] | 18 | from typing import Generator |
Rob Mohr | 8d13e25 | 2022-09-27 20:01:44 +0000 | [diff] [blame] | 19 | |
| 20 | from recipe_engine import recipe_api |
Rob Mohr | 8d13e25 | 2022-09-27 20:01:44 +0000 | [diff] [blame] | 21 | from RECIPE_MODULES.fuchsia.utils import nice_duration |
| 22 | |
| 23 | |
| 24 | class TimeoutApi(recipe_api.RecipeApi): |
| 25 | """Ensure the given call completes before swarming kills the build.""" |
| 26 | |
| 27 | @contextlib.contextmanager |
Rob Mohr | 0b9859a | 2024-03-06 23:25:38 +0000 | [diff] [blame^] | 28 | def __call__(self, buffer_sec: float = 120) -> Generator[None, None, None]: |
Rob Mohr | 7ff94c0 | 2023-11-20 17:01:28 +0000 | [diff] [blame] | 29 | current_time_sec: float = self.m.time.time() |
Rob Mohr | 8d13e25 | 2022-09-27 20:01:44 +0000 | [diff] [blame] | 30 | |
| 31 | # Amount of time elapsed in the run. |
Rob Mohr | 7ff94c0 | 2023-11-20 17:01:28 +0000 | [diff] [blame] | 32 | elapsed_time_sec: float = ( |
Rob Mohr | d607119 | 2023-06-15 22:17:01 +0000 | [diff] [blame] | 33 | current_time_sec - self.m.buildbucket.build.start_time.seconds |
Rob Mohr | 8d13e25 | 2022-09-27 20:01:44 +0000 | [diff] [blame] | 34 | ) |
| 35 | |
| 36 | # Amount of time before build times out. |
Rob Mohr | 7ff94c0 | 2023-11-20 17:01:28 +0000 | [diff] [blame] | 37 | time_remaining_sec: float = ( |
Rob Mohr | d607119 | 2023-06-15 22:17:01 +0000 | [diff] [blame] | 38 | self.m.buildbucket.build.execution_timeout.seconds |
| 39 | - elapsed_time_sec |
Rob Mohr | 8d13e25 | 2022-09-27 20:01:44 +0000 | [diff] [blame] | 40 | ) |
| 41 | |
| 42 | # Give a buffer before build times out and kill this step then. This |
| 43 | # should give enough time to read any logfiles and maybe upload to |
Rob Mohr | d607119 | 2023-06-15 22:17:01 +0000 | [diff] [blame] | 44 | # GCS before the build times out. |
Rob Mohr | 7ff94c0 | 2023-11-20 17:01:28 +0000 | [diff] [blame] | 45 | timeout_sec: float = time_remaining_sec - buffer_sec |
Rob Mohr | 8d13e25 | 2022-09-27 20:01:44 +0000 | [diff] [blame] | 46 | |
Rob Mohr | d607119 | 2023-06-15 22:17:01 +0000 | [diff] [blame] | 47 | # Most tests don't appropriately set up timing, and this could be |
| 48 | # invoked at the very end of a build where it's about to timeout, so |
| 49 | # make sure the timeout is always at least 10 seconds in the future. |
Rob Mohr | 7ff94c0 | 2023-11-20 17:01:28 +0000 | [diff] [blame] | 50 | if timeout_sec < 10.0: |
| 51 | timeout_sec = 10.0 |
Rob Mohr | 8d13e25 | 2022-09-27 20:01:44 +0000 | [diff] [blame] | 52 | |
Rob Mohr | d607119 | 2023-06-15 22:17:01 +0000 | [diff] [blame] | 53 | with self.m.step.nest(f'timeout {nice_duration(timeout_sec)}'): |
Rob Mohr | adee1d4 | 2023-03-28 21:30:26 +0000 | [diff] [blame] | 54 | pass |
Rob Mohr | 8d13e25 | 2022-09-27 20:01:44 +0000 | [diff] [blame] | 55 | |
Rob Mohr | 8d13e25 | 2022-09-27 20:01:44 +0000 | [diff] [blame] | 56 | try: |
Rob Mohr | 686cf71 | 2023-06-15 22:19:09 +0000 | [diff] [blame] | 57 | with self.m.time.timeout(timeout_sec): |
Rob Mohr | 8d13e25 | 2022-09-27 20:01:44 +0000 | [diff] [blame] | 58 | yield |
| 59 | |
| 60 | finally: |
| 61 | pass |