fix(adminui): close a browse session that opens after its picker is gone (R04 L4)
Every picker and RawBrowseModal stored the OpenAsync token after the await; if the host was disposed (or the modal closed) meanwhile, its teardown had already run with no token, so the plant-side session lived until the reaper's idle TTL. BrowseOpenGuard.CloseIfOrphaned closes it at once; each host sets _disposed first thing in DisposeAsync (RawBrowseModal also treats !Visible as gone). Refs #745 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
+5
@@ -240,6 +240,8 @@ else
|
||||
private string _built = "";
|
||||
private string _selectedColumnNodeId = "";
|
||||
private Guid _token = Guid.Empty;
|
||||
// Set first thing in DisposeAsync; an open that lands afterwards closes its own session.
|
||||
private volatile bool _disposed;
|
||||
private bool _opening;
|
||||
private bool _canOperate;
|
||||
private string? _openError;
|
||||
@@ -268,6 +270,8 @@ else
|
||||
// sole place it is read, and it dies with the local variable.
|
||||
var json = BuildBrowseConfig();
|
||||
var result = await BrowserService.OpenAsync(DriverTypeNames.Sql, json, default);
|
||||
// Host disposed mid-open: close the session nobody will (R04 L4).
|
||||
if (BrowseOpenGuard.CloseIfOrphaned(result, _disposed, BrowserService)) { return; }
|
||||
if (result.Ok) { _token = result.Token; }
|
||||
else { _openError = result.Message; }
|
||||
}
|
||||
@@ -429,6 +433,7 @@ else
|
||||
|
||||
public ValueTask DisposeAsync()
|
||||
{
|
||||
_disposed = true;
|
||||
if (_token != Guid.Empty)
|
||||
{
|
||||
// Fire-and-forget — don't block circuit teardown on a slow database.
|
||||
|
||||
Reference in New Issue
Block a user