From 7264e8f1f4a7841c4daf414a73e8345eb6793660 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 2 May 2026 13:55:25 +0000 Subject: [PATCH 1/3] Initial plan From e76722a3a3bad97b0c49a8a797e3c344d7a3425e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 2 May 2026 13:57:38 +0000 Subject: [PATCH 2/3] Update OpenTelemetry.Exporter packages to 1.15.3 to fix GHSA-4625-4j76-fww9 Agent-Logs-Url: https://github.com/jodavis/AdaptiveRemote/sessions/2a25fc1c-dd69-4762-a4d7-4c87cf614e29 Co-authored-by: jodavis <6740581+jodavis@users.noreply.github.com> --- Directory.Packages.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 18035c3..8636062 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -18,8 +18,8 @@ - - + + From d5468d538a54683846946bc0543df18bdba666f8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 2 May 2026 23:51:11 +0000 Subject: [PATCH 3/3] Add startup retry loop for transient WebView2 resource-in-use crash Agent-Logs-Url: https://github.com/jodavis/AdaptiveRemote/sessions/7c9c8221-a900-4e4d-8207-7eb2718f58c6 Co-authored-by: jodavis <6740581+jodavis@users.noreply.github.com> --- .../Host/AdaptiveRemoteHost.Builder.cs | 45 ++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/test/AdaptiveRemote.EndtoEndTests.TestServices/Host/AdaptiveRemoteHost.Builder.cs b/test/AdaptiveRemote.EndtoEndTests.TestServices/Host/AdaptiveRemoteHost.Builder.cs index 99409c9..2890f01 100644 --- a/test/AdaptiveRemote.EndtoEndTests.TestServices/Host/AdaptiveRemoteHost.Builder.cs +++ b/test/AdaptiveRemote.EndtoEndTests.TestServices/Host/AdaptiveRemoteHost.Builder.cs @@ -13,6 +13,9 @@ public partial class AdaptiveRemoteHost { public class Builder { + private const string ResourceInUseExceptionMessage = "The requested resource is in use."; + private const int StartupRetryCount = 3; + private AdaptiveRemoteHostSettings _settings; private readonly ILoggerFactory _loggerFactory; private readonly HostApplicationLoggerProvider _hostLoggerProvider; @@ -48,7 +51,35 @@ public AdaptiveRemoteHost Start(Func retryLogger = _loggerFactory.CreateLogger(); + + // Only HostStartupException instances whose CapturedOutput contains ResourceInUseExceptionMessage + // are retried. Any other exception (e.g. Inconclusive, process-launch failure) propagates immediately. + for (int attempt = 1; attempt <= StartupRetryCount; attempt++) + { + try + { + return StartWithSettings(effectiveSettings); + } + catch (HostStartupException ex) when (ex.CapturedOutput.Contains(ResourceInUseExceptionMessage, StringComparison.OrdinalIgnoreCase)) + { + if (attempt == StartupRetryCount) + { + throw; + } + + retryLogger.LogWarning( + "Host startup attempt {Attempt}/{MaxAttempts} failed with '{ExceptionMessage}'. Retrying...", + attempt, StartupRetryCount, ResourceInUseExceptionMessage); + Thread.Sleep(Random.Shared.Next(1000, 3000)); + } + } + + // Unreachable: the loop always exits via return (success) or throw (final-attempt failure + // re-throws via the catch block, or a non-retryable exception propagates immediately). + // Required by the compiler since it cannot prove the loop body always returns or throws. + throw new InvalidOperationException("Unexpected state: startup retry loop exited without returning or throwing."); } private AdaptiveRemoteHost StartWithSettings(AdaptiveRemoteHostSettings _settings) @@ -268,7 +299,7 @@ Failed to connect to the test control endpoint on port {ControlPort} within {Sta logger.LogError(processException, "Failed to kill the host process. {ErrorMessage}", processException.Message); } - throw; + throw new HostStartupException(ex.Message, ex, standardOutputAndError.ToString()); } } @@ -280,6 +311,16 @@ private static int GetAvailablePort() listener.Stop(); return port; } + + private sealed class HostStartupException(string message, Exception innerException, string capturedOutput) + : Exception(message, innerException) + { + /// + /// The captured stdout/stderr from the host process at the time of the startup failure. + /// Used by to identify retryable crashes (e.g., WebView2 resource-in-use). + /// + internal string CapturedOutput { get; } = capturedOutput; + } } }