From 0234185589c14af352727f0567cccc48c486be1f Mon Sep 17 00:00:00 2001 From: Jimmy Campbell Date: Fri, 17 Apr 2026 16:55:02 -0400 Subject: [PATCH 1/4] Update retry policy to be more resilient toward temporary issues. --- .../cli/command_modules/appconfig/_utils.py | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/appconfig/_utils.py b/src/azure-cli/azure/cli/command_modules/appconfig/_utils.py index 4985ec556c6..6f526b638f5 100644 --- a/src/azure-cli/azure/cli/command_modules/appconfig/_utils.py +++ b/src/azure-cli/azure/cli/command_modules/appconfig/_utils.py @@ -15,6 +15,7 @@ ResourceNotFoundError, RequiredArgumentMissingError, MutuallyExclusiveArgumentError) +from azure.core.pipeline.policies import RetryPolicy from azure.core.pipeline.transport import RequestsTransport # pylint: disable=no-name-in-module from ._client_factory import cf_configstore from ._constants import HttpHeaders, FeatureFlagConstants @@ -172,6 +173,23 @@ def send(self, request, **kwargs): # pylint: disable=arguments-differ def get_appconfig_data_client(cmd, name, connection_string, auth_mode, endpoint): azconfig_client = None + # Retry backoff schedule (exponential, factor=0.5, cap=30s, timeout=100s): + # Retry 1: 0.5s (cumulative: 0.5s) + # Retry 2: 1.0s (cumulative: 1.5s) + # Retry 3: 2.0s (cumulative: 3.5s) + # Retry 4: 4.0s (cumulative: 7.5s) + # Retry 5: 8.0s (cumulative: 15.5s) + # Retry 6: 16.0s (cumulative: 31.5s) + # Retry 7: 30.0s (cumulative: 61.5s) + # Retry 8: 30.0s (cumulative: 91.5s) + # Retry 9: timeout fires (~100s) + retry_policy = RetryPolicy( + retry_total=9, + retry_status=9, + retry_backoff_factor=0.5, + retry_backoff_max=30, + timeout=100 # seconds + ) if auth_mode == "anonymous": try: @@ -180,7 +198,8 @@ def get_appconfig_data_client(cmd, name, connection_string, auth_mode, endpoint) credential=AzureKeyCredential(key=""), id_credential="", user_agent=HttpHeaders.USER_AGENT, - transport=AuthHeaderRequestsTransport()) + transport=AuthHeaderRequestsTransport(), + retry_policy=retry_policy) except (ValueError, TypeError) as ex: raise CLIError("Failed to initialize AzureAppConfigurationClient due to an exception: {}".format(str(ex))) @@ -188,7 +207,8 @@ def get_appconfig_data_client(cmd, name, connection_string, auth_mode, endpoint) connection_string = resolve_connection_string(cmd, name, connection_string) try: azconfig_client = AzureAppConfigurationClient.from_connection_string(connection_string=connection_string, - user_agent=HttpHeaders.USER_AGENT) + user_agent=HttpHeaders.USER_AGENT, + retry_policy=retry_policy) except ValueError as ex: raise CLIError("Failed to initialize AzureAppConfigurationClient due to an exception: {}".format(str(ex))) @@ -216,7 +236,8 @@ def get_appconfig_data_client(cmd, name, connection_string, auth_mode, endpoint) try: azconfig_client = AzureAppConfigurationClient(credential=AppConfigurationCliCredential(cred, token_audience), base_url=endpoint, - user_agent=HttpHeaders.USER_AGENT) + user_agent=HttpHeaders.USER_AGENT, + retry_policy=retry_policy) except (ValueError, TypeError) as ex: raise CLIError("Failed to initialize AzureAppConfigurationClient due to an exception: {}".format(str(ex))) From 75690268af54933ac1c16053d329df7df6f167d0 Mon Sep 17 00:00:00 2001 From: Jimmy Campbell Date: Fri, 17 Apr 2026 17:03:00 -0400 Subject: [PATCH 2/4] At least two spaces before in-line comment. --- src/azure-cli/azure/cli/command_modules/appconfig/_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/azure-cli/azure/cli/command_modules/appconfig/_utils.py b/src/azure-cli/azure/cli/command_modules/appconfig/_utils.py index 6f526b638f5..7fc22243d93 100644 --- a/src/azure-cli/azure/cli/command_modules/appconfig/_utils.py +++ b/src/azure-cli/azure/cli/command_modules/appconfig/_utils.py @@ -188,7 +188,7 @@ def get_appconfig_data_client(cmd, name, connection_string, auth_mode, endpoint) retry_status=9, retry_backoff_factor=0.5, retry_backoff_max=30, - timeout=100 # seconds + timeout=100 # seconds ) if auth_mode == "anonymous": From c8f6a397243be3e3bb024183fa24b559f231f1ef Mon Sep 17 00:00:00 2001 From: Jimmy Campbell Date: Wed, 22 Apr 2026 13:03:54 -0400 Subject: [PATCH 3/4] Set retry count to a high number to handle how the retry policy ignores exponential backoff when the server responds with a retry-after error code. --- .../azure/cli/command_modules/appconfig/_utils.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/appconfig/_utils.py b/src/azure-cli/azure/cli/command_modules/appconfig/_utils.py index 7fc22243d93..5c1aa0a7061 100644 --- a/src/azure-cli/azure/cli/command_modules/appconfig/_utils.py +++ b/src/azure-cli/azure/cli/command_modules/appconfig/_utils.py @@ -183,9 +183,14 @@ def get_appconfig_data_client(cmd, name, connection_string, auth_mode, endpoint) # Retry 7: 30.0s (cumulative: 61.5s) # Retry 8: 30.0s (cumulative: 91.5s) # Retry 9: timeout fires (~100s) + # We set retry count to a high number to allow the retry policy to retry until the timeout is reached, + # as the presence of a retry-after header from the service will cause the retry policy to ignore the exponential backoff + retry_count = 9999 retry_policy = RetryPolicy( - retry_total=9, - retry_status=9, + retry_total=retry_count, + retry_connect=retry_count, + retry_read=retry_count, + retry_status=retry_count, retry_backoff_factor=0.5, retry_backoff_max=30, timeout=100 # seconds From e4d4305275053fcff54ce9efb4b1497d63b09a45 Mon Sep 17 00:00:00 2001 From: Jimmy Campbell Date: Wed, 22 Apr 2026 13:29:46 -0400 Subject: [PATCH 4/4] Update comment. --- .../cli/command_modules/appconfig/_utils.py | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/appconfig/_utils.py b/src/azure-cli/azure/cli/command_modules/appconfig/_utils.py index 5c1aa0a7061..9ca7d1965c4 100644 --- a/src/azure-cli/azure/cli/command_modules/appconfig/_utils.py +++ b/src/azure-cli/azure/cli/command_modules/appconfig/_utils.py @@ -173,18 +173,11 @@ def send(self, request, **kwargs): # pylint: disable=arguments-differ def get_appconfig_data_client(cmd, name, connection_string, auth_mode, endpoint): azconfig_client = None - # Retry backoff schedule (exponential, factor=0.5, cap=30s, timeout=100s): - # Retry 1: 0.5s (cumulative: 0.5s) - # Retry 2: 1.0s (cumulative: 1.5s) - # Retry 3: 2.0s (cumulative: 3.5s) - # Retry 4: 4.0s (cumulative: 7.5s) - # Retry 5: 8.0s (cumulative: 15.5s) - # Retry 6: 16.0s (cumulative: 31.5s) - # Retry 7: 30.0s (cumulative: 61.5s) - # Retry 8: 30.0s (cumulative: 91.5s) - # Retry 9: timeout fires (~100s) - # We set retry count to a high number to allow the retry policy to retry until the timeout is reached, - # as the presence of a retry-after header from the service will cause the retry policy to ignore the exponential backoff + # Configure retries with exponential backoff (factor=0.5) capped at 30 seconds, + # with an overall retry timeout of 100 seconds. + # We set retry count to a high number so the retry policy can continue retrying until + # the timeout is reached. The actual retry timing may vary, for example when the service + # returns a Retry-After header and the policy uses that delay instead of the exponential backoff. retry_count = 9999 retry_policy = RetryPolicy( retry_total=retry_count,