fix(driver-galaxy): resolve Medium code-review finding (Driver.Galaxy-009)
Fix two resource-management bugs in StartDeployWatcher / BuildDefaultHierarchySource:
(a) Replace the discarded `_ = StartAsync(...)` with an explicit task variable that
surfaces any synchronous InvalidOperationException (called-twice guard) rather than
silently swallowing it.
(b) Change both StartDeployWatcher and BuildDefaultHierarchySource to use ??= on
_ownedRepositoryClient so the first client created (by whichever path runs first)
is reused by the second path, preventing a second GalaxyRepositoryClient from being
created and the first from leaking past the driver's lifetime.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -445,17 +445,21 @@ public sealed class GalaxyDriver
|
||||
|
||||
// Reuse the lazily-built repository client (DiscoverAsync constructs it on demand).
|
||||
// If discovery hasn't run yet, build the client here so the watcher has a target.
|
||||
if (_ownedRepositoryClient is null)
|
||||
{
|
||||
_ownedRepositoryClient = MxGateway.Client.GalaxyRepositoryClient.Create(
|
||||
BuildClientOptions(_options.Gateway));
|
||||
}
|
||||
// Driver.Galaxy-009 fix: guard with ??= so if BuildDefaultHierarchySource later runs
|
||||
// it reuses this client rather than overwriting the field and leaking the first instance.
|
||||
_ownedRepositoryClient ??= MxGateway.Client.GalaxyRepositoryClient.Create(
|
||||
BuildClientOptions(_options.Gateway));
|
||||
|
||||
var source = new GatewayGalaxyDeployWatchSource(_ownedRepositoryClient);
|
||||
_deployWatcher = new DeployWatcher(source, _logger);
|
||||
_deployWatcher.OnRediscoveryNeeded += (_, args) => OnRediscoveryNeeded?.Invoke(this, args);
|
||||
|
||||
_ = _deployWatcher.StartAsync(CancellationToken.None);
|
||||
// StartAsync schedules the background loop and returns Task.CompletedTask immediately.
|
||||
// It throws InvalidOperationException synchronously if called twice (programming error).
|
||||
// Driver.Galaxy-009 fix: don't discard the return value — observe any synchronous throw.
|
||||
var startTask = _deployWatcher.StartAsync(CancellationToken.None);
|
||||
// The task is already completed (StartAsync is synchronous); surface any synchronous fault.
|
||||
if (startTask.IsFaulted) startTask.GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -1032,20 +1036,10 @@ public sealed class GalaxyDriver
|
||||
/// </summary>
|
||||
private IGalaxyHierarchySource BuildDefaultHierarchySource()
|
||||
{
|
||||
var gw = _options.Gateway;
|
||||
var clientOptions = new MxGatewayClientOptions
|
||||
{
|
||||
Endpoint = new Uri(gw.Endpoint, UriKind.Absolute),
|
||||
ApiKey = ResolveApiKey(gw.ApiKeySecretRef),
|
||||
UseTls = gw.UseTls,
|
||||
CaCertificatePath = gw.CaCertificatePath,
|
||||
ConnectTimeout = TimeSpan.FromSeconds(gw.ConnectTimeoutSeconds),
|
||||
DefaultCallTimeout = TimeSpan.FromSeconds(gw.DefaultCallTimeoutSeconds),
|
||||
StreamTimeout = gw.StreamTimeoutSeconds > 0
|
||||
? TimeSpan.FromSeconds(gw.StreamTimeoutSeconds)
|
||||
: null,
|
||||
};
|
||||
_ownedRepositoryClient = GalaxyRepositoryClient.Create(clientOptions);
|
||||
// Driver.Galaxy-009 fix: reuse a client that StartDeployWatcher may have already
|
||||
// created (??=) rather than always overwriting the field and leaking the first
|
||||
// instance. Both paths produce equivalent clients from the same options.
|
||||
_ownedRepositoryClient ??= GalaxyRepositoryClient.Create(BuildClientOptions(_options.Gateway));
|
||||
return new TracedGalaxyHierarchySource(
|
||||
new GatewayGalaxyHierarchySource(_ownedRepositoryClient), _options.MxAccess.ClientName);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user