From 86d3a026adaabca97ca1486591343e4200fe1be8 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 12:48:10 +0000 Subject: [PATCH] Restore-DbaDbSnapshot - Add retry logic for deadlock errors This fixes issue #9233 where Restore-DbaDbSnapshot occasionally fails with deadlock errors when restoring multiple databases in parallel. The deadlock occurs when: 1. One process executes RESTORE DATABASE (holds locks on master) 2. Another process calls Get-DbaDbSnapshot (queries system tables in master) The fix implements retry logic with exponential backoff: - Detects deadlock errors (SQL error 1205) - Retries up to 3 times with 2^n second delays (2s, 4s, 8s) - Logs retry attempts at verbose level - Preserves original error handling for non-deadlock errors Co-authored-by: Chrissy LeMaire --- public/Restore-DbaDbSnapshot.ps1 | 36 ++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/public/Restore-DbaDbSnapshot.ps1 b/public/Restore-DbaDbSnapshot.ps1 index 1c4ce11e610c..568e0f897a9e 100644 --- a/public/Restore-DbaDbSnapshot.ps1 +++ b/public/Restore-DbaDbSnapshot.ps1 @@ -166,14 +166,38 @@ function Restore-DbaDbSnapshot { # Need a proper restore now if ($Pscmdlet.ShouldProcess($server, "Restore db $db from $snap")) { - try { - if ($Force) { - $null = Stop-DbaProcess -SqlInstance $server -Database $db.Name, $snap.Name -WarningAction SilentlyContinue + $maxRetries = 3 + $retryCount = 0 + $restoreSuccess = $false + + while (-not $restoreSuccess -and $retryCount -lt $maxRetries) { + try { + if ($Force) { + $null = Stop-DbaProcess -SqlInstance $server -Database $db.Name, $snap.Name -WarningAction SilentlyContinue + } + + $null = $server.Query("USE master; RESTORE DATABASE [$($db.Name)] FROM DATABASE_SNAPSHOT='$($snap.Name)'") + $restoreSuccess = $true + } catch { + # Check if this is a deadlock error (error 1205) + if ($_.Exception.InnerException.Number -eq 1205) { + $retryCount++ + if ($retryCount -lt $maxRetries) { + $waitSeconds = [Math]::Pow(2, $retryCount) + Write-Message -Level Verbose -Message "Deadlock detected during restore of $db on $server. Retrying in $waitSeconds seconds (attempt $retryCount of $maxRetries)" + Start-Sleep -Seconds $waitSeconds + } else { + Stop-Function -Message "Failiure attempting to restore $db on $server after $maxRetries attempts due to deadlock" -ErrorRecord $_ -Continue + } + } else { + Stop-Function -Message "Failiure attempting to restore $db on $server" -ErrorRecord $_ -Continue + break + } } + } - $null = $server.Query("USE master; RESTORE DATABASE [$($db.Name)] FROM DATABASE_SNAPSHOT='$($snap.Name)'") - } catch { - Stop-Function -Message "Failiure attempting to restore $db on $server" -ErrorRecord $_ -Continue + if (-not $restoreSuccess) { + continue } }