Skip to content

Commit

Permalink
Fix pending binary builds (infra) (#897)
Browse files Browse the repository at this point in the history
* Fix pending binary builds

* Rolled back comment update

* New test for unknown buildstatus

* Motivate time sleep everywhere
  • Loading branch information
Hook25 authored Dec 14, 2023
1 parent 493a95a commit 88b54ea
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 6 deletions.
29 changes: 25 additions & 4 deletions tools/release/lp_build_monitor_recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def wait_every_source_build_started(build_recipe: LPSourcePackageRecipe):
" ",
)
)
# avoid flooding LP with requests
time.sleep(LP_POLLING_DELAY)
pending_builds = build_recipe.getPendingBuildInfo()

Expand All @@ -91,9 +92,14 @@ def get_all_binary_builds(
builds = build_recipe.daily_build_archive.getBuildRecords(
source_name=recipe_target
)

# date_first_dispatched is filled in once a build is dispatched
# and is the actual start time, it can be None if the build is
# still waiting to get picked up by a builder
return list(
itertools.takewhile(
lambda build: build.date_first_dispatched > started_datetime,
lambda build: build.date_first_dispatched is None
or build.date_first_dispatched >= started_datetime,
builds,
)
)
Expand All @@ -111,7 +117,7 @@ def get_all_source_builds(
# need
return list(
itertools.takewhile(
lambda build: build.date_first_dispatched > started_datetime,
lambda build: build.date_first_dispatched >= started_datetime,
build_recipe.builds,
)
)
Expand Down Expand Up @@ -196,15 +202,30 @@ def monitor_retry_builds(builds_to_check: list[LPBuild]) -> list[LPBuild]:
"Uploading build",
"Gathering build output",
]:
print(f"Build ongoing with status '{buildstate}'")
print(f" weblink: {build.web_link}")
# avoid flooding LP with requests
time.sleep(LP_POLLING_DELAY)
builds_to_check.insert(0, build)
print(f"Build ongoing with status '{buildstate}'")
elif buildstate not in [
"Failed to build",
"Dependency wait",
"Chroot problem",
"Failed to upload",
"Build for superseded Source",
"Cancelling build",
"Cancelled build",
]:
print(f"Unknown build status '{buildstate}'")
print(f" weblink: {build.web_link}")
elif build.can_be_retried:
# avoid flooding LP with requests
time.sleep(LP_POLLING_DELAY)
builds_to_check.insert(0, build)
elif build.can_be_retried:
print(f"Build failed with status '{buildstate}'")
print(f" retrying: {build.web_link}")
# avoid flooding LP with requests
time.sleep(LP_POLLING_DELAY)
build.retry()
builds_to_check.insert(0, build)
else:
Expand Down
34 changes: 32 additions & 2 deletions tools/release/test_lp_build_monitor_recipe.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import unittest

from unittest.mock import MagicMock, patch, call
from unittest.mock import MagicMock, patch

import lp_build_monitor_recipe

Expand All @@ -14,18 +14,25 @@ def test_get_all_binary_builds(self):
build_selected = MagicMock()
build_selected.date_first_dispatched = 10

build_selected_pending = MagicMock()
# pending builds have a None date_first_dispatched
# we select them because they are "newer" of the start date
# for sure given that they didn't even start yet
build_selected_pending.date_first_dispatched = None

build_not_selected = MagicMock()
build_not_selected.date_first_dispatched = 0

build_recipe.daily_build_archive.getBuildRecords.return_value = [
build_selected,
build_selected_pending,
build_not_selected,
]
selected = lp_build_monitor_recipe.get_all_binary_builds(
build_recipe, 6
)

self.assertEqual(selected, [build_selected])
self.assertEqual(selected, [build_selected, build_selected_pending])
build_recipe.daily_build_archive.getBuildRecords.assert_called_with(
source_name="checkbox-ng"
)
Expand Down Expand Up @@ -137,6 +144,29 @@ def lp_refresh_side_effect():
# each time a failure was detected, the build was retried
self.assertEqual(build_mock.retry.call_count, 3)

@patch("time.sleep")
def test_monitor_retry_builds_robust(self, time_sleep_mock):
build_mock = MagicMock()
# A build is updated via the lp_refresh function, lets do the same
# here but inject our test values
build_status_evolution = [
"Successfully built",
None # this may be possible for pending builds
]

def lp_refresh_side_effect():
if build_status_evolution:
build_mock.buildstate = build_status_evolution.pop()

build_mock.lp_refresh.side_effect = lp_refresh_side_effect

lp_build_monitor_recipe.monitor_retry_builds([build_mock])

# we updated till the build reported a success
self.assertEqual(build_mock.lp_refresh.call_count, 2)
# we didnt fload LP with requests, waiting once per progress
self.assertEqual(time_sleep_mock.call_count, 1)

@patch("time.sleep")
def test_monitor_retry_builds_more_wait(self, time_sleep_mock):
build_mock = MagicMock()
Expand Down

0 comments on commit 88b54ea

Please sign in to comment.