From a7cd617957bb2607c90ab4080a7e7c3a70302c5c Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Fri, 11 Sep 2026 20:49:46 +0000 Subject: [PATCH 1/2] fix(integration-tests): retry SAR ListApplications on throttling in setup fixture The get_serverless_application_repository_app fixture called sar_client.list_applications() with no throttle handling, so a TooManyRequestsException from SAR propagated out of fixture setup and errored every test depending on it. Wrap the call in a helper decorated with the existing retry_with_exponential_backoff_and_jitter(ThrottlingError, 5, 360), matching the treatment already applied to CloudFormation and S3 throttle-prone calls in the same file. --- integration/conftest.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/integration/conftest.py b/integration/conftest.py index 589b6ca04..04ac66feb 100644 --- a/integration/conftest.py +++ b/integration/conftest.py @@ -89,6 +89,22 @@ def _companion_stack_parameters(): return params +@retry_with_exponential_backoff_and_jitter(ThrottlingError, 5, 360) +def _sar_list_applications(sar_client): + """ + Wrap SAR ListApplications with the same throttle-retry treatment + the rest of this file applies to CloudFormation and S3 calls, so + a transient SAR throttle at fixture setup does not fail the whole test. + """ + try: + return sar_client.list_applications().get("Applications", []) + except botocore.exceptions.ClientError as ex: + error_code = ex.response.get("Error", {}).get("Code", "") + if error_code in ("TooManyRequestsException", "Throttling", "ThrottlingException"): + raise ThrottlingError(stack_name="SAR:list_applications", msg=str(ex)) + raise + + @pytest.fixture() def get_serverless_application_repository_app(): """Create or re-use a simple SAR app""" @@ -97,7 +113,7 @@ def get_serverless_application_repository_app(): return None sar_client = ClientProvider().sar_client - sar_apps = sar_client.list_applications().get("Applications", []) + sar_apps = _sar_list_applications(sar_client) for sar_app in sar_apps: if sar_app.get("Name") == SAR_APP_NAME: LOG.info("SAR Application was already created, skipping SAR application publish") From df543b46f8d9f9c09b219491671f7a7371ec7244 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Fri, 11 Sep 2026 21:04:01 +0000 Subject: [PATCH 2/2] fix(integration-tests): bound SAR throttle backoff and keep failure self-describing Address review feedback: - Base delay 360s meant up to ~6h of jittered sleeping before the call finally failed. The fixture is function-scoped and autoused by TestBasicApplication, so that cost is paid per test and would stall a shard until the CI job timeout. Use a 2s base delay, bounding total backoff to ~2 minutes. - retry_with_exponential_backoff_and_jitter raises exc_raise(exc_raise_msg) once retries are exhausted, which defaults to a bare Exception(""). Pass a message so a sustained throttle still names SAR in the CI log. --- integration/conftest.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/integration/conftest.py b/integration/conftest.py index 04ac66feb..0b75a7ef1 100644 --- a/integration/conftest.py +++ b/integration/conftest.py @@ -89,12 +89,22 @@ def _companion_stack_parameters(): return params -@retry_with_exponential_backoff_and_jitter(ThrottlingError, 5, 360) +@retry_with_exponential_backoff_and_jitter( + ThrottlingError, + 5, + 2, + exc_raise_msg="SAR ListApplications still throttled after 5 attempts", +) def _sar_list_applications(sar_client): """ Wrap SAR ListApplications with the same throttle-retry treatment the rest of this file applies to CloudFormation and S3 calls, so a transient SAR throttle at fixture setup does not fail the whole test. + + Unlike the CloudFormation and S3 helpers below, this uses a small base + delay: the fixture is function-scoped and autoused by TestBasicApplication, + so the backoff is paid per test. A read-only ListApplications throttle + clears in seconds, so ~1 minute of total backoff is enough. """ try: return sar_client.list_applications().get("Applications", [])