Skip to content

Commit ce446d2

Browse files
authored
3.53.1: Adds hotfix release 3.53.1 (#5377)
1 parent 6ff7e4f commit ce446d2

28 files changed

+4423
-74
lines changed

Directory.Build.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
22
<PropertyGroup>
3-
<ClientOfficialVersion>3.53.0</ClientOfficialVersion>
3+
<ClientOfficialVersion>3.53.1</ClientOfficialVersion>
44
<ClientPreviewVersion>3.54.0</ClientPreviewVersion>
5-
<ClientPreviewSuffixVersion>preview.0</ClientPreviewSuffixVersion>
5+
<ClientPreviewSuffixVersion>preview.1</ClientPreviewSuffixVersion>
66
<DirectVersion>3.39.1</DirectVersion>
77
<FaultInjectionVersion>1.0.0</FaultInjectionVersion>
88
<FaultInjectionSuffixVersion>beta.0</FaultInjectionSuffixVersion>

Microsoft.Azure.Cosmos/contracts/API_3.53.1.txt

Lines changed: 1758 additions & 0 deletions
Large diffs are not rendered by default.

Microsoft.Azure.Cosmos/contracts/API_3.54.0-preview.1.txt

Lines changed: 1892 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
//------------------------------------------------------------
4+
namespace Microsoft.Azure.Cosmos.Authorization
5+
{
6+
using System;
7+
using global::Azure.Core;
8+
9+
internal sealed class CosmosScopeProvider : IScopeProvider
10+
{
11+
private const string AadInvalidScopeErrorMessage = "AADSTS500011";
12+
private const string AadDefaultScope = "https://cosmos.azure.com/.default";
13+
private const string ScopeFormat = "https://{0}/.default";
14+
15+
private readonly string accountScope;
16+
private readonly string overrideScope;
17+
private string currentScope;
18+
19+
public CosmosScopeProvider(Uri accountEndpoint)
20+
{
21+
this.overrideScope = ConfigurationManager.AADScopeOverrideValue(defaultValue: null);
22+
this.accountScope = string.Format(ScopeFormat, accountEndpoint.Host);
23+
this.currentScope = this.overrideScope ?? this.accountScope;
24+
}
25+
26+
public TokenRequestContext GetTokenRequestContext()
27+
{
28+
return new TokenRequestContext(new[] { this.currentScope });
29+
}
30+
31+
public bool TryFallback(Exception exception)
32+
{
33+
// If override scope is set, never fallback
34+
if (!string.IsNullOrEmpty(this.overrideScope))
35+
{
36+
return false;
37+
}
38+
39+
// If already using fallback scope, do not fallback again
40+
if (this.currentScope == CosmosScopeProvider.AadDefaultScope)
41+
{
42+
return false;
43+
}
44+
45+
#pragma warning disable CDX1003 // DontUseExceptionToString
46+
if (exception.ToString().Contains(CosmosScopeProvider.AadInvalidScopeErrorMessage) == true)
47+
{
48+
this.currentScope = CosmosScopeProvider.AadDefaultScope;
49+
return true;
50+
}
51+
#pragma warning restore CDX1003 // DontUseExceptionToString
52+
53+
return false;
54+
}
55+
}
56+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
//------------------------------------------------------------
4+
namespace Microsoft.Azure.Cosmos.Authorization
5+
{
6+
using System;
7+
using global::Azure.Core;
8+
9+
internal interface IScopeProvider
10+
{
11+
TokenRequestContext GetTokenRequestContext();
12+
bool TryFallback(Exception ex);
13+
}
14+
}

Microsoft.Azure.Cosmos/src/Authorization/TokenCredentialCache.cs

Lines changed: 43 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ namespace Microsoft.Azure.Cosmos
1010
using System.Threading;
1111
using System.Threading.Tasks;
1212
using global::Azure;
13-
using global::Azure.Core;
13+
using global::Azure.Core;
14+
using Microsoft.Azure.Cosmos.Authorization;
1415
using Microsoft.Azure.Cosmos.Core.Trace;
1516
using Microsoft.Azure.Cosmos.Resource.CosmosExceptions;
1617
using Microsoft.Azure.Cosmos.Tracing;
@@ -36,9 +37,7 @@ internal sealed class TokenCredentialCache : IDisposable
3637
// If the background refresh fails with less than a minute then just allow the request to hit the exception.
3738
public static readonly TimeSpan MinimumTimeBetweenBackgroundRefreshInterval = TimeSpan.FromMinutes(1);
3839

39-
private const string ScopeFormat = "https://{0}/.default";
40-
41-
private readonly TokenRequestContext tokenRequestContext;
40+
private readonly IScopeProvider scopeProvider;
4241
private readonly TokenCredential tokenCredential;
4342
private readonly CancellationTokenSource cancellationTokenSource;
4443
private readonly CancellationToken cancellationToken;
@@ -51,7 +50,7 @@ internal sealed class TokenCredentialCache : IDisposable
5150
private Task<AccessToken>? currentRefreshOperation = null;
5251
private AccessToken? cachedAccessToken = null;
5352
private bool isBackgroundTaskRunning = false;
54-
private bool isDisposed = false;
53+
private bool isDisposed = false;
5554

5655
internal TokenCredentialCache(
5756
TokenCredential tokenCredential,
@@ -65,14 +64,7 @@ internal TokenCredentialCache(
6564
throw new ArgumentNullException(nameof(accountEndpoint));
6665
}
6766

68-
string? scopeOverride = ConfigurationManager.AADScopeOverrideValue(defaultValue: null);
69-
70-
this.tokenRequestContext = new TokenRequestContext(new string[]
71-
{
72-
!string.IsNullOrEmpty(scopeOverride)
73-
? scopeOverride
74-
: string.Format(TokenCredentialCache.ScopeFormat, accountEndpoint.Host)
75-
});
67+
this.scopeProvider = new Microsoft.Azure.Cosmos.Authorization.CosmosScopeProvider(accountEndpoint);
7668

7769
if (backgroundTokenCredentialRefreshInterval.HasValue)
7870
{
@@ -129,7 +121,7 @@ public void Dispose()
129121
}
130122

131123
this.cancellationTokenSource.Cancel();
132-
this.cancellationTokenSource.Dispose();
124+
this.cancellationTokenSource.Dispose();
133125
this.isDisposed = true;
134126
}
135127

@@ -171,11 +163,13 @@ private async Task<AccessToken> GetNewTokenAsync(
171163

172164
private async ValueTask<AccessToken> RefreshCachedTokenWithRetryHelperAsync(
173165
ITrace trace)
174-
{
166+
{
167+
Exception? lastException = null;
168+
const int totalRetryCount = 2;
169+
TokenRequestContext tokenRequestContext = default;
170+
175171
try
176172
{
177-
Exception? lastException = null;
178-
const int totalRetryCount = 2;
179173
for (int retry = 0; retry < totalRetryCount; retry++)
180174
{
181175
if (this.cancellationToken.IsCancellationRequested)
@@ -190,11 +184,13 @@ private async ValueTask<AccessToken> RefreshCachedTokenWithRetryHelperAsync(
190184
name: nameof(this.RefreshCachedTokenWithRetryHelperAsync),
191185
component: TraceComponent.Authorization,
192186
level: Tracing.TraceLevel.Info))
193-
{
187+
{
194188
try
195-
{
189+
{
190+
tokenRequestContext = this.scopeProvider.GetTokenRequestContext();
191+
196192
this.cachedAccessToken = await this.tokenCredential.GetTokenAsync(
197-
requestContext: this.tokenRequestContext,
193+
requestContext: tokenRequestContext,
198194
cancellationToken: this.cancellationToken);
199195

200196
if (!this.cachedAccessToken.HasValue)
@@ -219,32 +215,15 @@ private async ValueTask<AccessToken> RefreshCachedTokenWithRetryHelperAsync(
219215

220216
return this.cachedAccessToken.Value;
221217
}
222-
catch (RequestFailedException requestFailedException)
223-
{
224-
lastException = requestFailedException;
225-
getTokenTrace.AddDatum(
226-
$"RequestFailedException at {DateTime.UtcNow.ToString(CultureInfo.InvariantCulture)}",
227-
requestFailedException.Message);
228-
229-
DefaultTrace.TraceError($"TokenCredential.GetToken() failed with RequestFailedException. scope = {string.Join(";", this.tokenRequestContext.Scopes)}, retry = {retry}, Exception = {lastException.Message}");
230-
231-
// Don't retry on auth failures
232-
if (requestFailedException.Status == (int)HttpStatusCode.Unauthorized ||
233-
requestFailedException.Status == (int)HttpStatusCode.Forbidden)
234-
{
235-
this.cachedAccessToken = default;
236-
throw;
237-
}
238-
}
239218
catch (OperationCanceledException operationCancelled)
240219
{
241220
lastException = operationCancelled;
242221
getTokenTrace.AddDatum(
243222
$"OperationCanceledException at {DateTime.UtcNow.ToString(CultureInfo.InvariantCulture)}",
244-
operationCancelled.Message);
245-
246-
DefaultTrace.TraceError(
247-
$"TokenCredential.GetTokenAsync() failed. scope = {string.Join(";", this.tokenRequestContext.Scopes)}, retry = {retry}, Exception = {lastException.Message}");
223+
operationCancelled.Message);
224+
225+
DefaultTrace.TraceError(
226+
$"TokenCredential.GetTokenAsync() failed. scope = {string.Join(";", tokenRequestContext.Scopes)}, retry = {retry}, Exception = {lastException.Message}");
248227

249228
throw CosmosExceptionFactory.CreateRequestTimeoutException(
250229
message: ClientResources.FailedToGetAadToken,
@@ -255,15 +234,29 @@ private async ValueTask<AccessToken> RefreshCachedTokenWithRetryHelperAsync(
255234
innerException: lastException,
256235
trace: getTokenTrace);
257236
}
258-
catch (Exception exception)
259-
{
260-
lastException = exception;
261-
getTokenTrace.AddDatum(
262-
$"Exception at {DateTime.UtcNow.ToString(CultureInfo.InvariantCulture)}",
263-
exception.Message);
264-
265-
DefaultTrace.TraceError(
266-
$"TokenCredential.GetTokenAsync() failed. scope = {string.Join(";", this.tokenRequestContext.Scopes)}, retry = {retry}, Exception = {lastException.Message}");
237+
catch (Exception exception)
238+
{
239+
lastException = exception;
240+
getTokenTrace.AddDatum(
241+
$"Exception at {DateTime.UtcNow.ToString(CultureInfo.InvariantCulture)}",
242+
exception.Message);
243+
244+
DefaultTrace.TraceError($"TokenCredential.GetToken() failed with RequestFailedException. scope = {string.Join(";", tokenRequestContext.Scopes)}, retry = {retry}, Exception = {lastException.Message}");
245+
246+
// Don't retry on auth failures
247+
if (exception is RequestFailedException requestFailedException &&
248+
(requestFailedException.Status == (int)HttpStatusCode.Unauthorized ||
249+
requestFailedException.Status == (int)HttpStatusCode.Forbidden))
250+
{
251+
this.cachedAccessToken = default;
252+
throw;
253+
}
254+
bool didFallback = this.scopeProvider.TryFallback(exception);
255+
256+
if (didFallback)
257+
{
258+
DefaultTrace.TraceInformation($"TokenCredential.GetTokenAsync() failed. scope = {string.Join(";", tokenRequestContext.Scopes)}, retry = {retry}, Exception = {lastException.Message}. Fallback attempted: {didFallback}");
259+
}
267260
}
268261
}
269262
}

Microsoft.Azure.Cosmos/src/Diagnostics/CosmosTraceDiagnostics.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ public CosmosTraceDiagnostics(ITrace trace)
4040

4141
public override string ToString()
4242
{
43+
if (this.Value is Tracing.Trace rootConcreteTrace)
44+
{
45+
rootConcreteTrace.SetWalkingStateRecursively();
46+
}
47+
4348
return this.ToJsonString();
4449
}
4550

@@ -50,16 +55,31 @@ public override TimeSpan GetClientElapsedTime()
5055

5156
public override IReadOnlyList<(string regionName, Uri uri)> GetContactedRegions()
5257
{
58+
if (this.Value is Tracing.Trace rootConcreteTrace)
59+
{
60+
rootConcreteTrace.SetWalkingStateRecursively();
61+
}
62+
5363
return this.Value?.Summary?.RegionsContacted;
5464
}
5565

5666
public override ServerSideCumulativeMetrics GetQueryMetrics()
5767
{
68+
if (this.Value is Tracing.Trace rootConcreteTrace)
69+
{
70+
rootConcreteTrace.SetWalkingStateRecursively();
71+
}
72+
5873
return this.accumulatedMetrics.Value;
5974
}
6075

6176
internal bool IsGoneExceptionHit()
6277
{
78+
if (this.Value is Tracing.Trace rootConcreteTrace)
79+
{
80+
rootConcreteTrace.SetWalkingStateRecursively();
81+
}
82+
6383
return this.WalkTraceTreeForGoneException(this.Value);
6484
}
6585

Microsoft.Azure.Cosmos/src/Pagination/ParallelPrefetch.Testing.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ public int AwaitedTasks
5757

5858
IReadOnlyDictionary<string, object> ITrace.Data => this.innerTrace.Data;
5959

60+
bool ITrace.IsBeingWalked => this.innerTrace.IsBeingWalked;
61+
6062
public ParallelPrefetchTestConfig(
6163
ArrayPool<IPrefetcher> prefetcherPool,
6264
ArrayPool<Task> taskPool,
@@ -116,6 +118,11 @@ void IDisposable.Dispose()
116118
{
117119
this.innerTrace.Dispose();
118120
}
121+
122+
bool ITrace.TryGetDatum(string key, out object datum)
123+
{
124+
return this.innerTrace.TryGetDatum(key, out datum);
125+
}
119126
}
120127
}
121128
}

Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsTraceExtractor.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ public static void WalkTraceTreeForQueryMetrics(ITrace currentTrace, ServerSideM
1717
return;
1818
}
1919

20+
// Assert that walking state is set
21+
System.Diagnostics.Debug.Assert(currentTrace.IsBeingWalked, "SetWalkingStateRecursively should be set to true");
22+
2023
foreach (object datum in currentTrace.Data.Values)
2124
{
2225
if (datum is QueryMetricsTraceDatum queryMetricsTraceDatum)
@@ -41,6 +44,9 @@ private static void WalkTraceTreeForPartitionInfo(ITrace currentTrace, ServerSid
4144
return;
4245
}
4346

47+
// Assert that walking state is set
48+
System.Diagnostics.Debug.Assert(currentTrace.IsBeingWalked, "SetWalkingStateRecursively should be set to true");
49+
4450
foreach (Object datum in currentTrace.Data.Values)
4551
{
4652
if (datum is ClientSideRequestStatisticsTraceDatum clientSideRequestStatisticsTraceDatum)

Microsoft.Azure.Cosmos/src/Query/v3Query/QueryIterator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public override async Task<ResponseMessage> ReadNextAsync(ITrace trace, Cancella
180180

181181
// If Correlated Id already exists and is different, add a new one in comma separated list
182182
// Scenario: A new iterator is created with same ContinuationToken and Trace
183-
if (trace.Data.TryGetValue(QueryIterator.CorrelatedActivityIdKeyName, out object correlatedActivityIds))
183+
if (trace.TryGetDatum(QueryIterator.CorrelatedActivityIdKeyName, out object correlatedActivityIds))
184184
{
185185
List<string> correlatedIdList = correlatedActivityIds.ToString().Split(',').ToList();
186186
if (!correlatedIdList.Contains(this.correlatedActivityId.ToString()))

0 commit comments

Comments
 (0)