Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions dotnet/src/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2391,13 +2391,15 @@ public void Dispose()
/// </summary>
/// <returns>A <see cref="ValueTask"/> representing the asynchronous dispose operation.</returns>
/// <remarks>
/// This method calls <see cref="ForceStopAsync"/> to immediately release all resources.
/// This method calls <see cref="StopAsync"/> to gracefully shut down the runtime and
/// release all resources. Use <see cref="ForceStopAsync"/> for an immediate hard stop
/// that skips graceful runtime shutdown.
/// </remarks>
public async ValueTask DisposeAsync()
{
if (_disposed) return;
_disposed = true;
await ForceStopAsync();
await StopAsync();
}

private class RpcHandler(CopilotClient client)
Expand Down
14 changes: 14 additions & 0 deletions dotnet/test/Unit/ClientSessionLifetimeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ public async Task StopAsync_Requests_Runtime_Shutdown_For_Owned_Process()
Assert.Equal(1, server.RuntimeShutdownCount);
}

[Fact]
public async Task DisposeAsync_Requests_Runtime_Shutdown_For_Owned_Process()
{
await using var server = await FakeCopilotServer.StartAsync();
var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) });
await client.StartAsync();
using var process = StartExitedProcess();
await ReplaceConnectionCliProcessAsync(client, process);

await client.DisposeAsync();

Assert.Equal(1, server.RuntimeShutdownCount);
}

[Fact]
public async Task StopAsync_Does_Not_Throw_When_Runtime_Shutdown_Fails()
{
Expand Down
Loading