From 42cd5e4e507635dd2bc6d9e6c83bfdb48fc22ef5 Mon Sep 17 00:00:00 2001 From: Michael Jolley Date: Thu, 27 Aug 2026 18:31:20 -0500 Subject: [PATCH] Fix gallery cancellation after concurrent refresh Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b34be394-240f-4bdd-878f-41460bc09c36 --- .../Services/JsonRpcExtensionService.cs | 6 ++++++ .../JsonRpcExtensionServiceReconciliationTests.cs | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Services/JsonRpcExtensionService.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Services/JsonRpcExtensionService.cs index 08a317fc98..86398562cc 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Services/JsonRpcExtensionService.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Services/JsonRpcExtensionService.cs @@ -254,6 +254,12 @@ public sealed partial class JsonRpcExtensionService : IExtensionService, IJsExte { RaiseProviderAdded(wrapper); } + + if (timeoutCts.IsCancellationRequested) + { + cancellationToken.ThrowIfCancellationRequested(); + return false; + } } catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested) { diff --git a/src/modules/cmdpal/Tests/Microsoft.CmdPal.UI.ViewModels.UnitTests/JsonRpcExtensionServiceReconciliationTests.cs b/src/modules/cmdpal/Tests/Microsoft.CmdPal.UI.ViewModels.UnitTests/JsonRpcExtensionServiceReconciliationTests.cs index 51e05a7fd9..b98b362fc4 100644 --- a/src/modules/cmdpal/Tests/Microsoft.CmdPal.UI.ViewModels.UnitTests/JsonRpcExtensionServiceReconciliationTests.cs +++ b/src/modules/cmdpal/Tests/Microsoft.CmdPal.UI.ViewModels.UnitTests/JsonRpcExtensionServiceReconciliationTests.cs @@ -182,6 +182,20 @@ public class JsonRpcExtensionServiceReconciliationTests Assert.IsNull(manifest); } + [TestMethod] + public async Task RefreshAndAwaitProviderAsync_CallerCancellation_Throws() + { + using var service = new JsonRpcExtensionService(TaskScheduler.Default); + using var cancellationTokenSource = new CancellationTokenSource(); + cancellationTokenSource.Cancel(); + + await Assert.ThrowsExactlyAsync(() => + service.RefreshAndAwaitProviderAsync( + Path.Combine(_root, "missing"), + TimeSpan.FromSeconds(1), + cancellationTokenSource.Token)); + } + [TestMethod] public void GetExtensionDirectoryForPath_ReturnsOwningTopLevelDirectory() {