Skip to content

Commit e97eab5

Browse files
committed
fix: preserve async stream exception type (#358)
1 parent 57faa43 commit e97eab5

2 files changed

Lines changed: 29 additions & 8 deletions

File tree

EnumerableAsyncProcessor.UnitTests/AsyncEnumerableProcessorTests.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,34 @@ public async Task ForEachAsync_WithException_PropagatesException()
278278
var exception = await Assert.ThrowsAsync<InvalidOperationException>(async () => await task);
279279
await Assert.That(exception!.Message).IsEqualTo("Test exception");
280280
}
281+
282+
[Test, Timeout(10_000)]
283+
public async Task ForEachAsync_WithConcurrentExceptions_PropagatesOriginalException(
284+
CancellationToken cancellationToken)
285+
{
286+
var startedCount = 0;
287+
var workersStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
288+
var releaseWorkers = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
289+
290+
var task = GenerateAsyncEnumerable(2)
291+
.ForEachAsync(async _ =>
292+
{
293+
if (Interlocked.Increment(ref startedCount) == 2)
294+
{
295+
workersStarted.TrySetResult();
296+
}
297+
298+
await releaseWorkers.Task.WaitAsync(cancellationToken);
299+
throw new InvalidOperationException("Concurrent failure");
300+
})
301+
.ProcessInParallel(2)
302+
.ExecuteAsync();
303+
304+
await workersStarted.Task.WaitAsync(cancellationToken);
305+
releaseWorkers.TrySetResult();
306+
307+
await Assert.ThrowsAsync<InvalidOperationException>(() => task);
308+
}
281309

282310
[Test]
283311
public async Task ForEachAsync_ProcessInParallel_UnboundedConcurrency_ProcessesAllItems()

EnumerableAsyncProcessor/AsyncEnumerableWorkerPool.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -214,14 +214,7 @@ private static void ThrowIfFailed(
214214
{
215215
if (exceptions.TryDequeue(out var firstException))
216216
{
217-
if (exceptions.IsEmpty)
218-
{
219-
ExceptionDispatchInfo.Capture(firstException).Throw();
220-
}
221-
222-
var allExceptions = new List<Exception> { firstException };
223-
allExceptions.AddRange(exceptions);
224-
throw new AggregateException(allExceptions);
217+
ExceptionDispatchInfo.Capture(firstException).Throw();
225218
}
226219

227220
if (wasCanceled != 0)

0 commit comments

Comments
 (0)