Add cancellation handling to prevent UnobservedTaskException in Watcher#1827
Add cancellation handling to prevent UnobservedTaskException in Watcher#1827tg123 wants to merge 1 commit into
Conversation
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: tg123 The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
There was a problem hiding this comment.
Pull request overview
This PR fixes a watch-cancellation edge case where cancelling while an async read is in-flight can orphan the original task and later surface as TaskScheduler.UnobservedTaskException during finalization/shutdown.
Changes:
- Update
Watcher<T>.CreateWatchEventEnumeratorto ensure faulted orphan tasks are observed, preventingUnobservedTaskException. - On newer TFMs, pass the
CancellationTokendirectly intoReadLineAsync(...)to cancel the read itself. - Add a regression test that reproduces the orphaned-task scenario and asserts no
UnobservedTaskExceptionis raised.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/KubernetesClient/Watcher.cs |
Ensures faulted orphan tasks are observed; uses cancellation-aware read on newer TFMs. |
tests/KubernetesClient.Tests/WatchTests.cs |
Adds regression coverage to detect UnobservedTaskException during watch cancellation/fault scenarios. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| var unobservedExceptions = new List<Exception>(); | ||
| void Handler(object sender, UnobservedTaskExceptionEventArgs e) | ||
| { | ||
| unobservedExceptions.Add(e.Exception); | ||
| } |
| await Task.Delay(50).ConfigureAwait(true); | ||
| } | ||
|
|
||
| Assert.Empty(unobservedExceptions); |
follow up copilot ver #1814
fix #1813
Cancelling a watch's CancellationToken while ReadLineAsync() is in flight left the original read task orphaned. When the transport tore the connection down, that task faulted with an unobserved IOException, surfacing as a TaskScheduler.UnobservedTaskException at finalization (e.g. during app shutdown).
Root cause: AttachCancellationToken in CreateWatchEventEnumerator wraps the read via task.ContinueWith(..., cancellationToken). On cancellation the continuation is cancelled immediately while the original ReadLineAsync() keeps running and later faults — with no one observing it.