Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace Azure.Mcp.Core.Services.Azure;

public abstract class BaseAzureService
{
private const int MaxAllowedRetries = 10;
private static UserAgentPolicy s_sharedUserAgentPolicy;
private static string? s_userAgent;
private static volatile bool s_initialized = false;
Expand Down Expand Up @@ -198,7 +199,9 @@ protected static T ConfigureRetryPolicy<T>(T clientOptions, RetryPolicyOptions?
}
if (retryPolicy.HasMaxRetries)
{
clientOptions.Retry.MaxRetries = retryPolicy.MaxRetries;
// To prevent excessive retries, we enforce a maximum number of retries regardless of what the caller specifies.
// This is to protect against misconfiguration that could lead to very long retry loops.
clientOptions.Retry.MaxRetries = Math.Min(MaxAllowedRetries, retryPolicy.MaxRetries);
}
if (retryPolicy.HasMode)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,24 @@ public async Task GetArmAccessTokenAsync_NullTenant_PassesNullToGetTokenCredenti
await _tenantService.Received(1).GetTokenCredentialAsync(null, Arg.Any<CancellationToken>());
}

[Theory]
[InlineData(5, true, 5)] // below cap, should remain unchanged
[InlineData(10, true, 10)] // at cap, should remain unchanged
[InlineData(20, true, 10)] // above cap, should be capped
[InlineData(20, false, null)] // HasMaxRetries = false, should not override default
public void ConfigureRetryPolicy_RespectsAndCapsMaxRetries(int maxRetries, bool hasMaxRetries, int? expectedMaxRetries)
{
// Arrange
var retryPolicy = new RetryPolicyOptions { MaxRetries = maxRetries, HasMaxRetries = hasMaxRetries };
var clientOptions = new ArmClientOptions();
var defaultClientOptions = new ArmClientOptions();
// Act
_azureService.ConfigureRetryPolicyPublic(clientOptions, retryPolicy);
// Assert
var expected = expectedMaxRetries ?? defaultClientOptions.Retry.MaxRetries;
Assert.Equal(expected, clientOptions.Retry.MaxRetries);
}

private sealed class TestAzureService(ITenantService tenantService) : BaseAzureService(tenantService)
{
public Task<ArmClient> GetArmClientAsync(string? tenant = null, RetryPolicyOptions? retryPolicy = null) =>
Expand All @@ -232,5 +250,8 @@ public Task<AccessToken> GetArmAccessTokenPublicAsync(string? tenant, Cancellati
public string EscapeKqlStringTest(string value) => EscapeKqlString(value);

public string GetUserAgent() => UserAgent;

public T ConfigureRetryPolicyPublic<T>(T clientOptions, RetryPolicyOptions? retryPolicy) where T : ClientOptions =>
ConfigureRetryPolicy(clientOptions, retryPolicy);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pr: 2187
changes:
- section: "Other Changes"
description: "Added bounds for RetryPolicyOptions"