diff --git a/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosOperationCanceledException.cs b/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosOperationCanceledException.cs index 54c74e15d2..ecb48fa724 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosOperationCanceledException.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosOperationCanceledException.cs @@ -6,6 +6,7 @@ namespace Microsoft.Azure.Cosmos { using System; using System.Collections; + using System.Threading; using Microsoft.Azure.Cosmos.Diagnostics; using Microsoft.Azure.Cosmos.Tracing; @@ -18,6 +19,7 @@ public class CosmosOperationCanceledException : OperationCanceledException { private readonly OperationCanceledException originalException; private readonly Lazy lazyMessage; + private readonly Lazy toStringMessage; /// /// Create an instance of CosmosOperationCanceledException @@ -31,7 +33,8 @@ public CosmosOperationCanceledException( { this.originalException = originalException ?? throw new ArgumentNullException(nameof(originalException)); this.Diagnostics = diagnostics ?? throw new ArgumentNullException(nameof(diagnostics)); - this.lazyMessage = this.CreateLazyMessage(); + this.lazyMessage = this.CreateLazyMessage(originalException.CancellationToken); + this.toStringMessage = this.CreateToStringMessage(originalException.CancellationToken); } internal CosmosOperationCanceledException( @@ -47,7 +50,8 @@ internal CosmosOperationCanceledException( trace.AddDatum("Operation Cancelled Exception", originalException); this.Diagnostics = new CosmosTraceDiagnostics(trace); - this.lazyMessage = this.CreateLazyMessage(); + this.lazyMessage = this.CreateLazyMessage(originalException.CancellationToken); + this.toStringMessage = this.CreateToStringMessage(originalException.CancellationToken); } /// @@ -87,12 +91,17 @@ public override Exception GetBaseException() /// public override string ToString() { - return $"{this.originalException} {Environment.NewLine}CosmosDiagnostics: {this.Diagnostics}"; + return this.toStringMessage.Value; } - private Lazy CreateLazyMessage() + private Lazy CreateLazyMessage(CancellationToken token) { - return new Lazy(() => $"{this.originalException.Message} {Environment.NewLine}CosmosDiagnostics: {this.Diagnostics}"); + return new Lazy(() => $"{this.originalException.Message}{Environment.NewLine}Cancellation Token has expired: {token.IsCancellationRequested}. Learn more at: https://aka.ms/cosmosdb-tsg-request-timeout{Environment.NewLine}CosmosDiagnostics: {this.Diagnostics}"); + } + + private Lazy CreateToStringMessage(CancellationToken token) + { + return new Lazy(() => $"{this.originalException}{Environment.NewLine}Cancellation Token has expired: {token.IsCancellationRequested}. Learn more at: https://aka.ms/cosmosdb-tsg-request-timeout{Environment.NewLine}CosmosDiagnostics: {this.Diagnostics}"); } } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CancellationTokenTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CancellationTokenTests.cs index 560e477c26..bf1c1de749 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CancellationTokenTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CancellationTokenTests.cs @@ -176,6 +176,13 @@ StoreResponse sendDirectFunc(Uri uri, ResourceOperation resourceOperation, Docum ((MockDocumentClient)client.DocumentClient).MockGlobalEndpointManager.Verify(gep => gep.MarkEndpointUnavailableForRead(It.IsAny()), Times.Once, "Should had marked the endpoint unavailable"); ((MockDocumentClient)client.DocumentClient).MockGlobalEndpointManager.Verify(gep => gep.RefreshLocationAsync(false), Times.Once, "Should had refreshed the account information"); + + string expectedHelpLink = "https://aka.ms/cosmosdb-tsg-request-timeout"; + string expectedCancellationTokenStatus = $"Cancellation Token has expired: {cancellationToken.IsCancellationRequested}"; + Assert.IsTrue(ex.Message.Contains(expectedHelpLink)); + Assert.IsTrue(ex.Message.Contains(expectedCancellationTokenStatus)); + Assert.IsTrue(ex.ToString().Contains(expectedHelpLink)); + Assert.IsTrue(ex.ToString().Contains(expectedCancellationTokenStatus)); } }