Noticed in passing in PR #10634's description (Export-DbaCsv got its disconnect placed in a finally explicitly because "the sibling pattern in Invoke-DbaQuery places the disconnect after the catch and would miss it") — verified in source and recorded here so it is not lost.
Behavior
Invoke-DbaQuery opens a non-pooled connection per instance when it is not handed an open one (NonPooledConnection = $true, see #8491), and closes it after execution via the #10554 ownership pattern:
} catch {
Stop-Function -Message "[$instance] Failed during execution" -ErrorRecord $_ -Target $instance -Continue
}
# Only close the connection if Connect-DbaInstance opened a new one for us. ...
if ($isNewConnection) {
$null = $server | Disconnect-DbaInstance -Verbose:$false
}
The disconnect sits after the try/catch. When the query fails:
- without
-EnableException, the catch's -Continue moves to the next instance of the loop — the disconnect is skipped;
- with
-EnableException, Stop-Function throws — the disconnect is skipped as well.
Either way the freshly opened non-pooled connection stays checked out until the process exits. Non-pooled connections are precisely the ones nothing else will ever clean up. A retry loop around failing queries accumulates one sleeping session per attempt.
Fix shape
Move the ownership disconnect into a finally around the execution, exactly as Export-DbaCsv does since #10634 — the disconnect then runs on the success, failure and -Continue paths alike. A counting regression test per the #10633–#10635 pattern, with the failure path (a query that throws) asserted explicitly, proves it.
This issue was created by Claude and reviewed by Andreas Jordan.
Noticed in passing in PR #10634's description (Export-DbaCsv got its disconnect placed in a
finallyexplicitly because "the sibling pattern inInvoke-DbaQueryplaces the disconnect after the catch and would miss it") — verified in source and recorded here so it is not lost.Behavior
Invoke-DbaQueryopens a non-pooled connection per instance when it is not handed an open one (NonPooledConnection = $true, see #8491), and closes it after execution via the #10554 ownership pattern:The disconnect sits after the try/catch. When the query fails:
-EnableException, the catch's-Continuemoves to the next instance of the loop — the disconnect is skipped;-EnableException,Stop-Functionthrows — the disconnect is skipped as well.Either way the freshly opened non-pooled connection stays checked out until the process exits. Non-pooled connections are precisely the ones nothing else will ever clean up. A retry loop around failing queries accumulates one sleeping session per attempt.
Fix shape
Move the ownership disconnect into a
finallyaround the execution, exactly asExport-DbaCsvdoes since #10634 — the disconnect then runs on the success, failure and-Continuepaths alike. A counting regression test per the #10633–#10635 pattern, with the failure path (a query that throws) asserted explicitly, proves it.This issue was created by Claude and reviewed by Andreas Jordan.