Skip to content

Commit f96dd1f

Browse files
committed
Async Cache and Async Cache Nonblocking exception handling changes
- Added support to post-process the exception in above mentioned two cache classes that creates a shallow copy of specific exception types to prevent stack trace proliferation and rethrows them, while propagating all other exceptions unchanged. - Added support for TaskCanceledException, TimeoutException and OperationCanceledException in this drop
1 parent 5e1dd0c commit f96dd1f

3 files changed

Lines changed: 65 additions & 8 deletions

File tree

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// ------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
// ------------------------------------------------------------
4+
5+
namespace Microsoft.Azure.Cosmos
6+
{
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Text;
10+
using System.Threading.Tasks;
11+
12+
/// <summary>
13+
/// Utility for post-processing of exceptions.
14+
/// </summary>
15+
internal static class ExceptionHandlingUtility
16+
{
17+
/// <summary>
18+
/// Creates a shallow copy of specific exception types (e.g., TaskCanceledException, TimeoutException, OperationCanceledException)
19+
/// to prevent excessive stack trace growth and rethrows them. All other exceptions are propagated as-is.
20+
/// </summary>
21+
/// <param name="e">The exception to process.</param>
22+
/// <exception cref="TaskCanceledException">Thrown if the input exception is a TaskCanceledException.</exception>
23+
/// <exception cref="TimeoutException">Thrown if the input exception is a TimeoutException.</exception>
24+
/// <exception cref="OperationCanceledException">Thrown if the input exception is an OperationCanceledException.</exception>
25+
public static void CloneAndRethrowException(Exception e)
26+
{
27+
if (e is TaskCanceledException)
28+
{
29+
TaskCanceledException taskCanceledEx = new TaskCanceledException(e.Message, e.InnerException);
30+
taskCanceledEx.Data["Message"] = e.Data["Message"];
31+
throw taskCanceledEx;
32+
}
33+
34+
if (e is TimeoutException)
35+
{
36+
TimeoutException timeoutEx = new TimeoutException(e.Message, e.InnerException);
37+
timeoutEx.Data["Message"] = e.Data["Message"];
38+
throw timeoutEx;
39+
}
40+
41+
if (e is OperationCanceledException)
42+
{
43+
OperationCanceledException operationCanceledEx = new OperationCanceledException(e.Message, e.InnerException);
44+
operationCanceledEx.Data["Message"] = e.Data["Message"];
45+
throw operationCanceledEx;
46+
}
47+
48+
// For all other exceptions, throw the original exception.
49+
throw e;
50+
}
51+
}
52+
}

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,14 @@ public async Task<TValue> GetAsync(
148148
{
149149
return await generator;
150150
}
151-
catch (Exception) when (object.ReferenceEquals(actualValue, newLazyValue))
151+
catch (Exception ex) when (object.ReferenceEquals(actualValue, newLazyValue))
152152
{
153153
// If the lambda this thread added to values triggered an exception remove it from the cache.
154-
this.TryRemoveValue(key, actualValue);
155-
throw;
154+
this.TryRemoveValue(key, actualValue);
155+
156+
// Creates a shallow copy of specific exception types to prevent stack trace proliferation
157+
// and rethrows them, while propagating all other exceptions unchanged.
158+
ExceptionHandlingUtility.CloneAndRethrowException(ex);
156159
}
157160
}
158161

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,11 @@ public async Task<TValue> GetAsync(
114114
key,
115115
removed,
116116
e);
117-
}
118-
119-
throw;
117+
}
118+
119+
// Creates a shallow copy of specific exception types to prevent stack trace proliferation
120+
// and rethrows them, while propagating all other exceptions unchanged.
121+
ExceptionHandlingUtility.CloneAndRethrowException(e);
120122
}
121123

122124
return await this.UpdateCacheAndGetValueFromBackgroundTaskAsync(
@@ -158,7 +160,7 @@ public async Task<TValue> GetAsync(
158160
this.values.TryRemove(key, out _);
159161
throw;
160162
}
161-
}
163+
}
162164

163165
public void Set(
164166
TKey key,
@@ -279,7 +281,7 @@ public AsyncLazyWithRefreshTask(
279281

280282
public bool IsValueCreated => this.value != null;
281283

282-
public Task<T> GetValueAsync(
284+
public Task<T> GetValueAsync(
283285
Func<T, Task<T>> createValueFunc)
284286
{
285287
// The task was already created so just return it.

0 commit comments

Comments
 (0)