fix: idempotent HistorianSession.DisposeAsync + upfront cancellation check

This commit is contained in:
Joseph Doherty
2026-06-25 03:05:10 -04:00
parent ad2c02eb42
commit d2b00fcda5
@@ -13,6 +13,7 @@ public sealed class HistorianSession : IAsyncDisposable
private readonly HistorianGrpcConnection _connection;
private readonly HistorianGrpcHandshake.Session _session;
private readonly HistorianClientOptions _options;
private int _disposed;
/// <summary>Whether this session was opened read-only or write-enabled (the Open2 connection mode).</summary>
public HistorianSessionKind Kind { get; }
@@ -41,6 +42,7 @@ public sealed class HistorianSession : IAsyncDisposable
int maxValues,
[EnumeratorCancellation] CancellationToken ct = default)
{
ct.ThrowIfCancellationRequested();
var orch = new HistorianGrpcReadOrchestrator(_options);
IReadOnlyList<HistorianSample> rows = await Task.Run(
() => orch.RunRawQueryOnSession(_connection, _session.ClientHandle, tag, startUtc, endUtc, maxValues, ct), ct)
@@ -63,6 +65,7 @@ public sealed class HistorianSession : IAsyncDisposable
TimeSpan interval,
[EnumeratorCancellation] CancellationToken ct = default)
{
ct.ThrowIfCancellationRequested();
var orch = new HistorianGrpcReadOrchestrator(_options);
IReadOnlyList<HistorianAggregateSample> rows = await Task.Run(
() => orch.RunAggregateQueryOnSession(_connection, _session.ClientHandle, tag, startUtc, endUtc, mode, interval, ct), ct)
@@ -179,8 +182,11 @@ public sealed class HistorianSession : IAsyncDisposable
/// <summary>Disposes the underlying gRPC connection (closes the channel). The server-side session
/// also idle-expires on its own; this releases the local channel resources immediately.</summary>
public ValueTask DisposeAsync()
{
if (Interlocked.Exchange(ref _disposed, 1) == 0)
{
_connection.Dispose();
}
return ValueTask.CompletedTask;
}
}