diff --git a/src/ClaudeNest.Agent/Services/SessionManager.cs b/src/ClaudeNest.Agent/Services/SessionManager.cs index b90a5d0e..72bdf881 100644 --- a/src/ClaudeNest.Agent/Services/SessionManager.cs +++ b/src/ClaudeNest.Agent/Services/SessionManager.cs @@ -200,11 +200,12 @@ public async Task HealthCheckAsync() } catch { - // Process no longer exists — dispose handle immediately to free native resources + // Process no longer exists — mark session as crashed and clear process reference. + // Don't dispose Process here as SpawnProcessAsync/MonitorAdoptedProcessAsync may + // still be awaiting WaitForExitAsync() on the same instance. Let the owning code + // path handle disposal; the 1-hour cleanup will catch any stragglers. session.State = SessionState.Crashed; session.EndedAt = DateTime.UtcNow; - session.Process?.Dispose(); - session.Process = null; await NotifyStatusChangedAsync(session); } } diff --git a/src/ClaudeNest.Agent/Services/SignalRConnectionManager.cs b/src/ClaudeNest.Agent/Services/SignalRConnectionManager.cs index 64b73d07..ec523819 100644 --- a/src/ClaudeNest.Agent/Services/SignalRConnectionManager.cs +++ b/src/ClaudeNest.Agent/Services/SignalRConnectionManager.cs @@ -118,6 +118,11 @@ public async Task ConnectAsync(CancellationToken stoppingToken) await OnReconnected(_connection.ConnectionId); break; } + catch (OperationCanceledException) when (_stoppingToken.IsCancellationRequested) + { + _logger.LogInformation("Reconnection cancelled — agent is shutting down"); + break; + } catch (Exception ex) { _logger.LogWarning(ex, "Manual reconnection failed, retrying in {Delay}s...", delay.TotalSeconds);