Skip to content

Invoke-DbaAdvancedRestore - Leave the connection of the caller alone - #10576

Open
andreasjordan wants to merge 1 commit into
developmentfrom
fix-advancedrestore-connection-ownership
Open

Invoke-DbaAdvancedRestore - Leave the connection of the caller alone#10576
andreasjordan wants to merge 1 commit into
developmentfrom
fix-advancedrestore-connection-ownership

Conversation

@andreasjordan

Copy link
Copy Markdown
Collaborator

Type of Change

Purpose

Last command of the inventory in #10554, and the one with the widest reach: Restore-DbaDatabase connects once and hands that server object down to here, so the connection that gets closed is the one its caller passed in.

Write-Message -Level Verbose -Message "Closing Server connection"
$server.ConnectionContext.Disconnect()

That sits in the finally of the loop over the backup files, so it fires after every single backup file. Verified on SQL Server 2019 with Connect-DbaInstance -NonPooledConnection and a temp table as the session marker:

=== Restore-DbaDatabase with a connection of the caller ===
  before: IsOpen True, database master
  after Restore-DbaDatabase
    IsOpen          : False
    session survived: False

=== Invoke-DbaAdvancedRestore directly with a connection of the caller ===
  before: IsOpen True
  after Invoke-DbaAdvancedRestore
    IsOpen          : False
    session survived: False

Approach

Connect-DbaInstance reports through IsNewConnectionReference whether it opened the connection, and only a connection opened here is closed.

The per-backup-file disconnect is gone rather than guarded. Reconnecting between the files of one restore chain serves nothing - SMO opens the connection again for the next file anyway.

The disconnect at the end of the loop over the databases was guarded by $server.ConnectionContext.exists:

if ($server.ConnectionContext.exists) {
    $server.ConnectionContext.Disconnect()
}

exists is not a property of a ServerConnection, so the condition was always $null and the block never ran. It now runs once, after all databases are done, and only for a connection this command opened itself.

Two things checked while in there and deliberately left alone:

  • $server.ConnectionContext.Connect() after killing processes or dropping the database is idempotent on an open connection and does not lose the session, so it stays as it is.
  • The progress bars in this command are odd in places, but they belong to the separate progress-bar cleanup and are not touched here.

The only other change is the verbose message in the catch, which said the server connection was being closed - the catch has never done that.

Commands to test

$server = Connect-DbaInstance -SqlInstance $instance -NonPooledConnection
$null = $server.ConnectionContext.ExecuteNonQuery("CREATE TABLE #t (id int)")
$null = Restore-DbaDatabase -SqlInstance $server -Path $backupFolder -WithReplace
$server.ConnectionContext.ExecuteScalar("SELECT COUNT(*) FROM #t")   # 0, was: Invalid object name '#t'

Tests

tests\Invoke-DbaAdvancedRestore.Tests.ps1 had unit tests only. Three integration contexts were added on InstanceSingle, all against a full plus a log backup so that the restore really runs more than one backup file - a single file would not show the disconnect that sat inside that loop:

  • the command called with a server object of the caller leaves the connection open, the session intact and the database context unchanged, and still restores every file
  • Restore-DbaDatabase with a server object of the caller does the same, which is the path this reaches in practice
  • called with an instance name, the command still opens and closes its own connection, restores every file and does not warn

14 tests, all passing. Against development 3 of them fail, covering both the direct call and the Restore-DbaDatabase path.

馃 Generated with Claude Code

The command closed the connection after every single backup file, no matter
who opened it. On a session-scoped connection that takes the session of the
caller with it, and Restore-DbaDatabase connects once and hands that server
object down to here, so this is the connection of its caller that is closed.

Connect-DbaInstance now reports through IsNewConnectionReference whether it
opened the connection, and only a connection opened here is closed.

The per-backup-file disconnect is gone. Reconnecting between the files of one
restore chain serves nothing, SMO just opens the connection again for the next
file. The disconnect at the end was guarded by ConnectionContext.exists, which
is not a property of a ServerConnection, so it never ran at all; it now runs
once after all databases are done, for a connection this command owns.

While in there: the verbose message in the catch said the server connection was
being closed, which the catch has never done.

(do Invoke-DbaAdvancedRestore, Restore-DbaDatabase)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Commands disconnect SQL Server connections they do not own

1 participant