Skip to content

Commit 843e8b9

Browse files
author
Alex Peck
committed
fix
1 parent aefdf90 commit 843e8b9

File tree

4 files changed

+89
-3
lines changed

4 files changed

+89
-3
lines changed

BitFaster.Caching.UnitTests/Atomic/AsyncAtomicFactoryTests.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,45 @@ await Task.WhenAll(first, second)
156156
}
157157
}
158158

159+
[Fact]
160+
public async Task WhenValueCreateThrowsDoesNotCauseUnobservedTaskException()
161+
{
162+
bool unobservedExceptionThrown = false;
163+
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
164+
165+
try
166+
{
167+
await AsyncAtomicFactoryGetValueAsync();
168+
169+
GC.Collect();
170+
GC.WaitForPendingFinalizers();
171+
}
172+
finally
173+
{
174+
TaskScheduler.UnobservedTaskException -= OnUnobservedTaskException;
175+
}
176+
177+
unobservedExceptionThrown.Should().BeFalse();
178+
179+
void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
180+
{
181+
unobservedExceptionThrown = true;
182+
e.SetObserved();
183+
}
184+
185+
static async Task AsyncAtomicFactoryGetValueAsync()
186+
{
187+
var a = new AsyncAtomicFactory<int, int>();
188+
try
189+
{
190+
_ = await a.GetValueAsync(12, i => throw new ArithmeticException());
191+
}
192+
catch (ArithmeticException)
193+
{
194+
}
195+
}
196+
}
197+
159198
[Fact]
160199
public void WhenValueNotCreatedHashCodeIsZero()
161200
{

BitFaster.Caching.UnitTests/Atomic/ScopedAsyncAtomicFactoryTests.cs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,6 @@ public async Task WhenCallersRunConcurrentlyResultIsFromWinner()
156156
winnerCount.Should().Be(1);
157157
}
158158

159-
160159
[Fact]
161160
public async Task WhenCallersRunConcurrentlyWithFailureSameExceptionIsPropagated()
162161
{
@@ -199,6 +198,48 @@ await Task.WhenAll(first, second)
199198
}
200199
}
201200

201+
[Fact]
202+
public async Task WhenValueCreateThrowsDoesNotCauseUnobservedTaskException()
203+
{
204+
bool unobservedExceptionThrown = false;
205+
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
206+
207+
try
208+
{
209+
await AsyncAtomicFactoryGetValueAsync();
210+
211+
GC.Collect();
212+
GC.WaitForPendingFinalizers();
213+
}
214+
finally
215+
{
216+
TaskScheduler.UnobservedTaskException -= OnUnobservedTaskException;
217+
}
218+
219+
unobservedExceptionThrown.Should().BeFalse();
220+
221+
void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
222+
{
223+
unobservedExceptionThrown = true;
224+
e.SetObserved();
225+
}
226+
227+
static async Task AsyncAtomicFactoryGetValueAsync()
228+
{
229+
var a = new ScopedAsyncAtomicFactory<int, IntHolder>();
230+
try
231+
{
232+
_ = await a.TryCreateLifetimeAsync(1, k =>
233+
{
234+
throw new ArithmeticException();
235+
});
236+
}
237+
catch (ArithmeticException)
238+
{
239+
}
240+
}
241+
}
242+
202243
[Fact]
203244
public async Task WhenDisposedWhileInitResultIsDisposed()
204245
{

BitFaster.Caching/Atomic/AsyncAtomicFactory.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,10 @@ public async ValueTask<V> CreateValueAsync<TFactory>(K key, TFactory valueFactor
159159
{
160160
Volatile.Write(ref isInitialized, false);
161161
tcs.SetException(ex);
162-
throw;
162+
163+
// always await the task to avoid unobserved task exceptions - normal case is that no other task is waiting.
164+
// this will re-throw the exception.
165+
await tcs.Task.ConfigureAwait(false);
163166
}
164167
}
165168

BitFaster.Caching/Atomic/ScopedAsyncAtomicFactory.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,10 @@ public async ValueTask<Scoped<V>> CreateScopeAsync<TFactory>(K key, TFactory val
178178
{
179179
Volatile.Write(ref isTaskInitialized, false);
180180
tcs.SetException(ex);
181-
throw;
181+
182+
// always await the task to avoid unobserved task exceptions - normal case is that no other task is waiting.
183+
// this will re-throw the exception.
184+
await tcs.Task.ConfigureAwait(false);
182185
}
183186
}
184187

0 commit comments

Comments
 (0)