fix: tighten table lock detection regex and log actual errors

The broad "locked" pattern was matching non-lock errors, causing
false retries. Now only matches specific BC lock messages. Also
surfaces the actual error text in WARN log lines for diagnostics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-16 20:17:28 +01:00
parent c81f4c51fb
commit 1ea3127a1d

View File

@@ -120,30 +120,37 @@ function Invoke-BCApi {
$errorBody = $_.ErrorDetails.Message
}
# Table lock: BC returns 500 with "being updated in a transaction"
$isTableLock = $errorBody -match "transaction done by another session|being updated in a transaction|deadlock|locked"
# Log the actual error so we can diagnose issues
$shortError = if ($errorBody.Length -gt 200) { $errorBody.Substring(0, 200) + "..." } else { $errorBody }
if (-not $shortError) { $shortError = "$_" }
# Table lock: BC returns 500 with very specific wording
$isTableLock = $errorBody -match "transaction done by another session|being updated in a transaction|deadlock victim"
# Rate limit
$isThrottled = ($statusCode -eq 429)
# Server error
$isServerError = ($statusCode -ge 500 -and -not $isTableLock)
# Timeout
$isTimeout = ($_ -match "Timeout")
# Other server errors (500+)
$isServerError = ($statusCode -ge 500 -and -not $isTableLock)
$isRetryable = $isTableLock -or $isThrottled -or $isServerError -or $isTimeout
if ($isRetryable -and $attempt -lt $MaxRetries) {
if ($isTableLock) {
# Table locks can last a while - wait longer with jitter
$wait = [math]::Min(30 + ($attempt * 15), 120)
Write-Log " Table lock detected (attempt $attempt/$MaxRetries), waiting ${wait}s..." "WARN"
Write-Log " Table lock (attempt $attempt/$MaxRetries), waiting ${wait}s... Error: $shortError" "WARN"
}
elseif ($isThrottled) {
$wait = [math]::Min(30 * $attempt, 300)
Write-Log " Rate limited (attempt $attempt/$MaxRetries), waiting ${wait}s..." "WARN"
}
elseif ($isTimeout) {
$wait = [math]::Min(15 * $attempt, 120)
Write-Log " Timeout (attempt $attempt/$MaxRetries), retrying in ${wait}s..." "WARN"
}
else {
$wait = [math]::Min(10 * $attempt, 120)
Write-Log " Request failed (attempt $attempt/$MaxRetries), retrying in ${wait}s..." "WARN"
$wait = [math]::Min(15 * $attempt, 120)
Write-Log " HTTP $statusCode (attempt $attempt/$MaxRetries), retrying in ${wait}s... Error: $shortError" "WARN"
}
Start-Sleep -Seconds $wait
continue
@@ -212,7 +219,7 @@ function Export-EntityData {
}
catch {
$errorMsg = "$_"
$isTableLock = $errorMsg -match "transaction done by another session|being updated in a transaction|deadlock|locked"
$isTableLock = $errorMsg -match "transaction done by another session|being updated in a transaction|deadlock victim"
if ($isTableLock -and $entityAttempt -lt $maxEntityRetries) {
$wait = 60 * $entityAttempt
@@ -324,7 +331,7 @@ function Export-DocumentWithLines {
}
catch {
$errorMsg = "$_"
$isTableLock = $errorMsg -match "transaction done by another session|being updated in a transaction|deadlock|locked"
$isTableLock = $errorMsg -match "transaction done by another session|being updated in a transaction|deadlock victim"
if ($isTableLock -and $entityAttempt -lt $maxEntityRetries) {
$wait = 60 * $entityAttempt