Skip to content
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions src/azure-cli/azure/cli/command_modules/appconfig/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -172,6 +173,28 @@ 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
Comment thread
jimmyca15 marked this conversation as resolved.
Outdated
retry_count = 9999
retry_policy = RetryPolicy(
retry_total=retry_count,
retry_connect=retry_count,
retry_read=retry_count,
retry_status=retry_count,
Comment thread
jimmyca15 marked this conversation as resolved.
Outdated
retry_backoff_factor=0.5,
retry_backoff_max=30,
timeout=100 # seconds
)
Comment on lines +182 to +190

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ChristineWanjau I'm still not familiar with the cli test setup. Should we set these as module constants, then mock them out so we can have some tests for them.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the cli test setup, currently we only have integration tests which are recorded http request/response pairs. They are then replayed in an automation environment without actually making any http calls. I don't think we can test retry in the integration tests since we can't trigger errors or record the retry behavior. https://github.com/Azure/azure-cli/blob/dev/doc/authoring_tests.md

We can also test the retries using mock unit tests. Although I am wondering how would that look like? Do we mock http responses to return 503s, 429s. The check if the retry policy works? What did you have in mind in terms of the tests?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mrm9084 , what is it that you would like to test? Testing the retry policy is out of scope. Did you want to have some tests that the client created in the internal method has the correct retry policy values via some assertion in the tests?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just thinking we might want some sort of test on our retry policy. I hadn't put too much thought into it.


if auth_mode == "anonymous":
try:
Expand All @@ -180,15 +203,17 @@ 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)))

if auth_mode == "key":
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)))

Expand Down Expand Up @@ -216,7 +241,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)))

Expand Down
Loading