Skip to content

Commit f4d737b

Browse files
Enhanced async exception handling and tests
- Added two unit tests in `BasicTests.cs` for verifying exception handling in async operations. These tests focus on ensuring `OperationCanceledException` is properly thrown and handled in custom async receivers. - Introduced a using directive for `System.Net.Mime.MediaTypeNames` in `Extensions.Pipe.cs` for consistency or new functionality support. - Improved exception handling in the async pipeline within `Extensions.Pipe.cs`. The update specifically enhances the handling of `OperationCanceledException` in task continuations, ensuring exceptions are correctly identified and managed. - Updated project metadata in `Open.ChannelExtensions.csproj`, incrementing the version to 8.4.2. This update includes changes to the package release notes, mentioning the addition of new `.Merge`, `.PipeAsync`, and `.PropagateCompletion` extensions, indicating preparation for a new library release.
1 parent b1f4df0 commit f4d737b

File tree

3 files changed

+53
-3
lines changed

3 files changed

+53
-3
lines changed

Open.ChannelExtensions.Tests/BasicTests.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,4 +513,37 @@ public static async Task PipeFilterAsyncTest()
513513
even.Should().OnlyContain(e => e % 2 == 0);
514514
odd.Should().OnlyContain(e => e % 2 != 0);
515515
}
516+
517+
[Fact]
518+
public static async Task ChannelReadAllAsyncExceptionTest()
519+
{
520+
static ValueTask<int> AsyncReceiver()
521+
=> throw new OperationCanceledException("test exception");
522+
523+
// Should throw.
524+
await Assert.ThrowsAsync<OperationCanceledException>(
525+
async () => await Enumerable.Repeat(0, 10)
526+
.ToChannel()
527+
.ReadAllAsync(async _ => await AsyncReceiver())
528+
);
529+
}
530+
531+
[Fact]
532+
public static async Task PipeAsyncReadAllExceptionTest()
533+
{
534+
static ValueTask<int> AsyncReceiver()
535+
=> throw new OperationCanceledException("test exception");
536+
537+
// Should also throw.
538+
await Assert.ThrowsAsync<OperationCanceledException>(
539+
async () =>
540+
{
541+
var reader = Enumerable.Repeat(0, 10)
542+
.ToChannel()
543+
.PipeAsync(1, async _ => await AsyncReceiver());
544+
545+
_ = await reader.ReadAll(_ => { });
546+
});
547+
}
548+
516549
}

Open.ChannelExtensions/Extensions.Pipe.cs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace Open.ChannelExtensions;
1+
using static System.Net.Mime.MediaTypeNames;
2+
3+
namespace Open.ChannelExtensions;
24

35
[SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "In order to differentiate between non async versions.")]
46
public static partial class Extensions
@@ -98,7 +100,22 @@ public static ChannelReader<TOut> PipeAsync<TIn, TOut>(this ChannelReader<TIn> s
98100
: ValueNotReady(result, cancellationToken); // Result is not ready, so we need to wait for it.
99101
}, cancellationToken)
100102
.ContinueWith(
101-
t => writer.Complete(t.Exception),
103+
t =>
104+
{
105+
Exception? ex = t.Exception;
106+
107+
/* We could have been cancelled
108+
* via a thrown cancel exception
109+
* that is not triggered by the token. */
110+
if (ex is null
111+
&& t.Status is TaskStatus.Canceled
112+
&& !cancellationToken.IsCancellationRequested)
113+
{
114+
ex = new OperationCanceledException();
115+
}
116+
117+
writer.Complete(ex);
118+
},
102119
CancellationToken.None,
103120
TaskContinuationOptions.ExecuteSynchronously,
104121
TaskScheduler.Current);

Open.ChannelExtensions/Open.ChannelExtensions.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<RepositoryType>git</RepositoryType>
2323
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
2424
<GenerateDocumentationFile>true</GenerateDocumentationFile>
25-
<Version>8.4.1</Version>
25+
<Version>8.4.2</Version>
2626
<PackageReleaseNotes>Added .Merge, .PipeAsync, and .PropagateCompletion extensions.</PackageReleaseNotes>
2727
<PackageLicenseExpression>MIT</PackageLicenseExpression>
2828
<PublishRepositoryUrl>true</PublishRepositoryUrl>

0 commit comments

Comments
 (0)