Skip to content

Commit 8ab0077

Browse files
committed
Modified the ExceptionHandlingUtility to TryClone model and letting the caller throw the exception
1 parent 6fdac6b commit 8ab0077

6 files changed

Lines changed: 12805 additions & 12806 deletions

File tree

Microsoft.Azure.Cosmos/src/ExceptionHandlingUtility.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,20 @@ namespace Microsoft.Azure.Cosmos
1616
internal static class ExceptionHandlingUtility
1717
{
1818
/// <summary>
19-
/// Creates a shallow copy of specific exception types (e.g., TaskCanceledException, TimeoutException, OperationCanceledException)
20-
/// to prevent excessive stack trace growth and rethrows them. All other exceptions are not processed.
19+
/// Tries to create a shallow copy of specific exception types (e.g., TaskCanceledException, TimeoutException, OperationCanceledException)
20+
/// to prevent excessive stack trace growth. Returns true if the exception was cloned, otherwise false.
2121
/// </summary>
22-
public static void CloneAndRethrowException(Exception e)
22+
public static bool TryCloneException(Exception e, out Exception clonedException)
2323
{
24-
Exception ex = e switch
24+
clonedException = e switch
2525
{
2626
ICloneable cloneableEx => (Exception)cloneableEx.Clone(),
2727
TaskCanceledException taskCanceledEx => AddMessageData(new TaskCanceledException(taskCanceledEx.Message, taskCanceledEx), e),
2828
TimeoutException timeoutEx => AddMessageData(new TimeoutException(timeoutEx.Message, timeoutEx), e),
2929
_ => null
3030
};
3131

32-
if (ex is not null)
33-
{
34-
throw ex;
35-
}
32+
return clonedException is not null;
3633
}
3734

3835
private static Exception AddMessageData(Exception target, Exception source)

Microsoft.Azure.Cosmos/src/Routing/AsyncCache.cs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -159,21 +159,29 @@ public async Task<TValue> GetAsync(
159159
this.TryRemoveValue(key, actualValue);
160160

161161
if (this.enableAsyncCacheExceptionNoSharing)
162-
{
163-
// Creates a shallow copy of specific exception types to prevent stack trace proliferation
164-
// and rethrows them, doesn't process other exceptions.
165-
ExceptionHandlingUtility.CloneAndRethrowException(ex);
166-
}
162+
{
163+
// Creates a shallow copy of specific exception types to prevent stack trace proliferation
164+
// and rethrows them, doesn't process other exceptions.
165+
if (ExceptionHandlingUtility.TryCloneException(ex, out Exception clone))
166+
{
167+
throw clone;
168+
}
169+
}
170+
167171
throw;
168172
}
169173
catch (Exception ex)
170174
{
171175
if (this.enableAsyncCacheExceptionNoSharing)
172-
{
173-
// Creates a shallow copy of specific exception types to prevent stack trace proliferation
174-
// and rethrows them, doesn't process other exceptions.
175-
ExceptionHandlingUtility.CloneAndRethrowException(ex);
176+
{
177+
// Creates a shallow copy of specific exception types to prevent stack trace proliferation
178+
// and rethrows them, doesn't process other exceptions.
179+
if (ExceptionHandlingUtility.TryCloneException(ex, out Exception clone))
180+
{
181+
throw clone;
182+
}
176183
}
184+
177185
throw;
178186
}
179187

Microsoft.Azure.Cosmos/src/Routing/AsyncCacheNonBlocking.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,10 @@ public async Task<TValue> GetAsync(
125125
{
126126
// Creates a shallow copy of specific exception types to prevent stack trace proliferation
127127
// and rethrows them, doesn't process other exceptions.
128-
ExceptionHandlingUtility.CloneAndRethrowException(e);
128+
if (ExceptionHandlingUtility.TryCloneException(e, out Exception clone))
129+
{
130+
throw clone;
131+
}
129132
}
130133
throw;
131134
}
@@ -172,7 +175,10 @@ public async Task<TValue> GetAsync(
172175
{
173176
// Creates a shallow copy of specific exception types to prevent stack trace proliferation
174177
// and rethrows them, doesn't process other exceptions.
175-
ExceptionHandlingUtility.CloneAndRethrowException(e);
178+
if (ExceptionHandlingUtility.TryCloneException(e, out Exception clone))
179+
{
180+
throw clone;
181+
}
176182
}
177183
throw;
178184
}

Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs

Lines changed: 39 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -937,35 +937,43 @@ public async Task MultiRegionAccountTest()
937937
Assert.IsNotNull(cosmosClient);
938938
AccountProperties properties = await cosmosClient.ReadAccountAsync();
939939
Assert.IsNotNull(properties);
940-
}
940+
}
941941

942942
[DataTestMethod]
943943
[DataRow(true)]
944944
[DataRow(false)]
945945
[Owner("amudumba")]
946946
public async Task ValidateAsyncExceptionNoSharing(bool asyncCacheExceptionNoSharing)
947947
{
948-
TimeoutException exception = new TimeoutException("HTTP Timeout exception", new TimeoutException("Inner exception message"));
949-
CosmosClientOptions cosmosClientOptions = new CosmosClientOptions()
950-
{
948+
TimeoutException exception = new TimeoutException("HTTP Timeout exception", new TimeoutException("Inner exception message"));
949+
int expectedHandlers = 3;
950+
int enteredHandlers = 0;
951+
TaskCompletionSource<object> blockSendingHandlers = new(TaskCreationOptions.RunContinuationsAsynchronously);
952+
953+
CosmosClientOptions cosmosClientOptions = new CosmosClientOptions()
954+
{
951955
ConsistencyLevel = Cosmos.ConsistencyLevel.Session,
952-
//Set the pre-request event handler to throw a pre-defined timeout exception.
953-
SendingRequestEventArgs = (sender, e) =>
954-
{
955-
if (e.IsHttpRequest())
956-
{
957-
string endWith = "partitionKeyRangeIds=0";
958-
if (e.HttpRequest.RequestUri.OriginalString.EndsWith(endWith))
959-
{
960-
if (e.HttpRequest.Method == HttpMethod.Get &&
961-
e.HttpRequest.RequestUri.OriginalString.EndsWith(endWith))
962-
{
963-
throw exception;
964-
}
965-
}
966-
}
967-
},
968-
EnableAsyncCacheExceptionNoSharing = asyncCacheExceptionNoSharing
956+
SendingRequestEventArgs = async (sender, e) =>
957+
{
958+
if (e.IsHttpRequest())
959+
{
960+
string endWith = "partitionKeyRangeIds=0";
961+
if (e.HttpRequest.Method == HttpMethod.Get &&
962+
e.HttpRequest.RequestUri.OriginalString.EndsWith(endWith))
963+
{
964+
// Wait until all expected threads are in the handler
965+
if (Interlocked.Increment(ref enteredHandlers) == expectedHandlers)
966+
{
967+
blockSendingHandlers.SetResult(null);
968+
}
969+
970+
await blockSendingHandlers.Task; // block here until all enter
971+
972+
throw exception;
973+
}
974+
}
975+
},
976+
EnableAsyncCacheExceptionNoSharing = asyncCacheExceptionNoSharing
969977
};
970978

971979
Cosmos.Database db = null;
@@ -976,29 +984,20 @@ public async Task ValidateAsyncExceptionNoSharing(bool asyncCacheExceptionNoShar
976984
db = await cosmosClient.CreateDatabaseIfNotExistsAsync("TimeoutFaultTest");
977985
Container container = await db.CreateContainerIfNotExistsAsync("TimeoutFaultContainer", "/pk");
978986

979-
// Shared TaskCompletionSource ensures all tasks start together
980-
TaskCompletionSource<object> tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
981-
int iterations = 3;// Simulating 3 concurrent write requests
982-
List<Task> createTasks = new List<Task>();
987+
int iterations = expectedHandlers;
988+
List<Task> createTasks = new();
983989

984-
for (int i = 0; i < iterations; i++)
985-
{
986-
createTasks.Add(Task.Run(async () =>
987-
{
988-
await tcs.Task; // All tasks wait before proceeding
989-
990-
ToDoActivity testItem = ToDoActivity.CreateRandomToDoActivity();
991-
await container.CreateItemAsync(testItem);
992-
}));
993-
}
994-
995-
// Signal all tasks to start
996-
tcs.SetResult(null);
990+
for (int i = 0; i < iterations; i++)
991+
{
992+
createTasks.Add(Task.Run(async () =>
993+
{
994+
ToDoActivity testItem = ToDoActivity.CreateRandomToDoActivity();
995+
await container.CreateItemAsync(testItem);
996+
}));
997+
}
997998

998999
// Wait for all tasks to complete (they should all fail)
9991000
await Task.WhenAll(createTasks);
1000-
1001-
10021001
}
10031002
catch (TimeoutException tex)
10041003
{

0 commit comments

Comments
 (0)