Skip to content

Commit 405b340

Browse files
authored
Merge pull request #644 from MicrosoftDocs/live
Sync branches up
2 parents 71eb0d7 + a4b8404 commit 405b340

1 file changed

Lines changed: 7 additions & 119 deletions

File tree

msal-dotnet-articles/advanced/exceptions/retry-policy.md

Lines changed: 7 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -3,129 +3,17 @@ title: Retry policies
33
description: Learn how to implement a custom retry policy for token acquisition operations in .NET with MSAL. Increase your service availability with our detailed guide.
44
---
55

6-
# Retry policies
6+
# Retry Policies are baked in the libary
77

8-
This document explains how to implement a custom retry policy around token acquisition operations. For other tips on how to increase the availability of your service, see [High Availability](../high-availability.md).
8+
MSAL has its own retry policies. In rare cases you can choose to disable the internal retry policies and add your own. See [HttpClient tips](../httpclient.md).
99

10-
## Better HTTP stack
10+
### MSAL implements a simple "retry-once" for errors with HTTP error codes 5xx
1111

12-
The default HTTP stack in .NET is not great. See [HttpClient tips](../httpclient.md) for details.
12+
MSAL.NET implements a simple retry-once with 1 second delay mechanism for errors with HTTP error codes 500-600, for the token endpoint.
13+
For managed identity, the retry follows the guidelines of each source.
1314

14-
## MSAL implements a simple "retry-once" for errors with HTTP error codes 5xx
15+
## Customize the HTTP stack
1516

16-
MSAL.NET implements a simple retry-once mechanism for errors with HTTP error codes 500-600. For more control / availability, consider disabling the default retry policy and define your own.
17+
In some cases, such as using proxies, you might want to customize the Http Stack. See [HttpClient tips](../httpclient.md) for details.
1718

18-
Note that Microsoft Entra ID may return a Retry-After header indicating to clients to pause for a few seconds, which needs to be taken into account.
1919

20-
## Example Retry policy
21-
22-
```csharp
23-
public async Task<AuthenticationResult> GetTokenAsync()
24-
{
25-
var app = ConfidentialClientApplicationBuilder.Create(ClientId)
26-
.WithClientSecret(ClientSecret)
27-
.WithHttpClientFactory(
28-
// consider using a higly scalable HttpClient, the default one is not great.
29-
// See /dotnet/fundamentals/networking/http/httpclient-guidelines#recommended-use
30-
httpClientFactory: null,
31-
32-
// Disable MSAL's internal simple retry policy
33-
retryOnceOn5xx: false)
34-
.Build();
35-
36-
// For caching see /azure/active-directory/develop/msal-net-token-cache-serialization?tabs=aspnet#in-memory-token-cache-1
37-
app.AddInMemoryCache();
38-
39-
AsyncRetryPolicy retryPolicy = GetMsalRetryPolicy();
40-
41-
AuthenticationResult result = await retryPolicy.ExecuteAsync(
42-
() => app.AcquireTokenForClient(TestConstants.s_scope.ToArray()).ExecuteAsync())
43-
.ConfigureAwait(false);
44-
45-
return result;
46-
}
47-
48-
private static AsyncRetryPolicy GetMsalRetryPolicy()
49-
{
50-
// Retry policy at token request level
51-
TimeSpan retryAfter = TimeSpan.Zero;
52-
53-
var retryPolicy = Policy.Handle<Exception>(ex =>
54-
{
55-
return IsMsalRetryableException(ex, out retryAfter);
56-
}).WaitAndRetryAsync(new[] // simple retry 0s, 3s, 5s + and "retry after" hint from the server
57-
{
58-
retryAfter, // could be 0
59-
retryAfter + TimeSpan.FromSeconds(2),
60-
retryAfter + TimeSpan.FromSeconds(5),
61-
},
62-
onRetry: (ex, ts) =>
63-
// Do some logging
64-
Debug.WriteLine($"MSAL call failed. Trying again after {ts}. Exception was {ex}"));
65-
66-
return retryPolicy;
67-
}
68-
69-
/// <summary>
70-
/// Retry any MsalException marked as retryable - see IsRetryable property and HttpRequestException
71-
/// If Retry-After header is present, return the value.
72-
/// </summary>
73-
/// <remarks>
74-
/// In MSAL 4.47.2 IsRetryable includes HTTP 408, 429 and 5xx Azure AD errors but may be expanded to transient Azure AD errors in the future.
75-
/// </remarks>
76-
private static bool IsMsalRetryableException(Exception ex, out TimeSpan retryAfter)
77-
{
78-
retryAfter = TimeSpan.Zero;
79-
80-
if (ex is HttpRequestException)
81-
return true;
82-
83-
if (ex is MsalException msalException && msalException.IsRetryable)
84-
{
85-
if (msalException is MsalServiceException msalServiceException)
86-
{
87-
retryAfter = GetRetryAfterValue(msalServiceException.Headers);
88-
}
89-
90-
return true;
91-
}
92-
93-
return false;
94-
}
95-
96-
private static TimeSpan GetRetryAfterValue(HttpResponseHeaders headers)
97-
{
98-
var date = headers?.RetryAfter?.Date;
99-
if (date.HasValue)
100-
{
101-
return date.Value - DateTimeOffset.Now;
102-
}
103-
104-
var delta = headers?.RetryAfter?.Delta;
105-
if (delta.HasValue)
106-
{
107-
return delta.Value;
108-
}
109-
110-
return TimeSpan.Zero;
111-
}
112-
```
113-
114-
## Retry Policy at HTTP level or at MSAL level?
115-
116-
The example above shows how to introduce a retry policy at MSAL level, since MSAL transforms HTTP errors 5xx into MSAL specific exceptions.
117-
It is also possible, to use an HTTP level retry policy, which can be introduced directly via the HttpClient.
118-
119-
Both possibilities are valid, with a slight preference for library-level retry policy. The reason for this is that we are trying to classify more exceptions as retry-able, for example Microsoft Entra error AADSTS50087 (see [Microsoft Entra error codes](/azure/active-directory/develop/reference-aadsts-error-codes#aadsts-error-codes) for full list). Tracking [work item](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/3649).
120-
121-
## Fallback instead of retry
122-
123-
Internally, Microsoft Entra ID uses several fallback mechanisms which help applications retrieve tokens even when Microsoft Entra ID is struggling. Regional token issuers (ESTS-R) automatically fallback to the global issuer if they go down. An emergency token issuer, which does not depend on Azure infrastructure, takes over if Microsoft Entra goes down.
124-
125-
Client applications do not need to do anything to benefit from these measures.
126-
127-
## What is the Retry-After header?
128-
129-
When the Security Token Service (STS) is too busy or having problems, it returns an HTTP error [429](https://developer.mozilla.org/docs/Web/HTTP/Status/429). It may also return other HTTP error codes, such as 503. Alongside the response it will add a [Retry-After header](https://developer.mozilla.org/docs/Web/HTTP/Headers/Retry-After), which indicates that the client should wait before calling again. The wait delay is in seconds, as per spec.
130-
131-
`MsalServiceException` surfaces `System.Net.Http.Headers.HttpResponseHeaders` as a property named `Headers`. You can therefore leverage additional information to the Error code to improve the reliability of your applications. In the case we just described, you can use the `RetryAfter` property (of type `RetryConditionHeaderValue`) and compute when to retry.

0 commit comments

Comments
 (0)