Skip to content

Commit

Permalink
Merge pull request #497 from microsoft/fix/retry-attributes
Browse files Browse the repository at this point in the history
fix/retry attributes
  • Loading branch information
baywet authored Dec 19, 2024
2 parents cfe9df9 + 56e8b47 commit 533634a
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 8 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.16.1] - 2024-12-18

### Changed

- Aligned retry open telemetry attributes names with latest specification. [#324](https://github.com/microsoft/kiota-dotnet/issues/324)
- Fixed a bug where the client would fail on 301/302 responses with no location headers. [#272](https://github.com/microsoft/kiota-dotnet/issues/272)

## [1.16.0] - 2024-12-13
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>
<!-- Common default project properties for ALL projects-->
<PropertyGroup>
<VersionPrefix>1.16.0</VersionPrefix>
<VersionPrefix>1.16.1</VersionPrefix>
<VersionSuffix></VersionSuffix>
<!-- This is overidden in test projects by setting to true-->
<IsTestProject>false</IsTestProject>
Expand Down
4 changes: 3 additions & 1 deletion src/http/httpClient/HttpClientRequestAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,8 @@ private async Task<HttpResponseMessage> GetHttpResponseMessageAsync(RequestInfor
/// </summary>
public const string AuthenticateChallengedEventKey = "com.microsoft.kiota.authenticate_challenge_received";

internal const string RetryCountAttributeName = "http.request.resend_count";

private async Task<HttpResponseMessage> RetryCAEResponseIfRequiredAsync(HttpResponseMessage response, RequestInformation requestInfo, CancellationToken cancellationToken, string? claims, Activity? activityForAttributes)
{
using var span = activitySource?.StartActivity(nameof(RetryCAEResponseIfRequiredAsync));
Expand All @@ -554,7 +556,7 @@ private async Task<HttpResponseMessage> RetryCAEResponseIfRequiredAsync(HttpResp
return response;
}
span?.AddEvent(new ActivityEvent(AuthenticateChallengedEventKey));
activityForAttributes?.SetTag("http.retry_count", 1);
activityForAttributes?.SetTag(RetryCountAttributeName, 1);
requestInfo.Content?.Seek(0, SeekOrigin.Begin);
await DrainAsync(response, cancellationToken).ConfigureAwait(false);
return await GetHttpResponseMessageAsync(requestInfo, cancellationToken, activityForAttributes, responseClaims).ConfigureAwait(false);
Expand Down
13 changes: 7 additions & 6 deletions src/http/httpClient/Middleware/RetryHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,12 @@ private async Task<HttpResponseMessage> SendRetryAsync(HttpResponseMessage respo
{
exceptions.Add(await GetInnerExceptionAsync(response).ConfigureAwait(false));
using var retryActivity = activitySource?.StartActivity($"{nameof(RetryHandler)}_{nameof(SendAsync)} - attempt {retryCount}");
retryActivity?.SetTag("http.retry_count", retryCount);
retryActivity?.SetTag(HttpClientRequestAdapter.RetryCountAttributeName, retryCount);
retryActivity?.SetTag("http.response.status_code", response.StatusCode);

// Call Delay method to get delay time from response's Retry-After header or by exponential backoff
Task delay = RetryHandler.DelayAsync(response, retryCount, retryOption.Delay, out double delayInSeconds, cancellationToken);
var delay = DelayAsync(response, retryCount, retryOption.Delay, out double delayInSeconds, cancellationToken);
retryActivity?.SetTag("http.request.resend_delay", delayInSeconds);

// If client specified a retries time limit, let's honor it
if(retryOption.RetriesTimeLimit > TimeSpan.Zero)
Expand Down Expand Up @@ -176,12 +177,12 @@ private static void AddOrUpdateRetryAttempt(HttpRequestMessage request, int retr
/// <param name="delayInSeconds"></param>
/// <param name="cancellationToken">The cancellationToken for the Http request</param>
/// <returns>The <see cref="Task"/> for delay operation.</returns>
internal static Task DelayAsync(HttpResponseMessage response, int retryCount, int delay, out double delayInSeconds, CancellationToken cancellationToken)
static internal Task DelayAsync(HttpResponseMessage response, int retryCount, int delay, out double delayInSeconds, CancellationToken cancellationToken)
{
delayInSeconds = delay;
if(response.Headers.TryGetValues(RetryAfter, out IEnumerable<string>? values))
if(response.Headers.TryGetValues(RetryAfter, out var values))
{
using IEnumerator<string> v = values.GetEnumerator();
using var v = values.GetEnumerator();
string retryAfter = v.MoveNext() ? v.Current : throw new InvalidOperationException("Retry-After header is empty.");
// the delay could be in the form of a seconds or a http date. See https://httpwg.org/specs/rfc7231.html#header.retry-after
if(int.TryParse(retryAfter, out int delaySeconds))
Expand All @@ -200,7 +201,7 @@ internal static Task DelayAsync(HttpResponseMessage response, int retryCount, in
delayInSeconds = CalculateExponentialDelay(retryCount, delay);
}

TimeSpan delayTimeSpan = TimeSpan.FromSeconds(Math.Min(delayInSeconds, RetryHandlerOption.MaxDelay));
var delayTimeSpan = TimeSpan.FromSeconds(Math.Min(delayInSeconds, RetryHandlerOption.MaxDelay));
delayInSeconds = delayTimeSpan.TotalSeconds;
return Task.Delay(delayTimeSpan, cancellationToken);
}
Expand Down

0 comments on commit 533634a

Please sign in to comment.