Skip to content

Commit 60c2cc5

Browse files
author
Uwe Janke
committed
1.9.3.0: Fix AlwaysOn-Job-Propagierung und sqm_BackupExclude-Werte-Sync auf Secondaries
- New-sqmOlaUsrDbBackupJob: Propagierung auf Secondaries lief nur bei JobStatus='Created', nicht bei 'Updated'/'AlreadyExists' - Secondaries blieben nach dem ersten Lauf ohne spaetere Aenderungen. - Sync-sqmBackupExcludeTable: IsActive/Reason-Werte der Primary wurden nie per MERGE auf Secondaries uebertragen, nur die Datenbank-Liste strukturell abgeglichen.
1 parent 22403c3 commit 60c2cc5

4 files changed

Lines changed: 69 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,32 @@
11
# sqmSQLTool — Changelog
22

3+
## [1.9.3.0] — 2026-07-03
4+
5+
### Fix: AlwaysOn-Propagierung fehlte/griff nicht zuverlaessig
6+
7+
**Problem gemeldet:** Jobs fehlten auf Secondary-Repliken; `sqm_BackupExclude`-Aenderungen
8+
(IsActive/Reason, ueber `Show-sqmBackupExcludeForm` gesetzt) kamen nie auf Secondaries an.
9+
10+
- **Fix `New-sqmOlaUsrDbBackupJob`**: die AlwaysOn-Job-Propagierung am Funktionsende pruefte nur
11+
`JobStatus -eq 'Created'`. Bei jedem Folgelauf (Job existiert bereits auf der Primary ->
12+
`JobStatus = 'Updated'` oder `'AlreadyExists'`) wurde die Bedingung `$false` und die
13+
Propagierung auf Secondaries lief **gar nicht mehr** - Secondaries blieben nach dem allerersten
14+
Lauf dauerhaft ohne die Jobs bzw. ohne spaetere Aenderungen (z.B. geaenderte Zeitplaene). Jetzt
15+
wird bei `'Created'`, `'Updated'` UND `'AlreadyExists'` propagiert (New-sqmOlaUsrDbBackupJob ist
16+
auf der Secondary ohnehin idempotent per `-Update`).
17+
- **Fix `Sync-sqmBackupExcludeTable`**: die AlwaysOn-Propagierung rief auf jeder Secondary nur
18+
rekursiv `Sync-sqmBackupExcludeTable` auf - das erkennt dort ausschliesslich NEUE/geloeschte
19+
Datenbanken lokal, uebertraegt aber **niemals** die vom Admin gesetzten `IsActive`/`Reason`-
20+
Werte der Primary. Der DDL-Trigger (`Register-sqmBackupExcludeTrigger`) deckt nur
21+
CREATE_DATABASE/DROP_DATABASE ab, ebenfalls keine Werte-Propagierung. Ergebnis: eine ueber die
22+
GUI gesetzte Ausschluss-Entscheidung erreichte Secondaries **nie**, auch nicht ueber den
23+
periodischen Sync-Job. Fix: nach dem strukturellen Abgleich wird der aktuelle Datenstand der
24+
Primary jetzt zusaetzlich per `MERGE` (IsActive/Reason) auf jede Secondary uebertragen. Auf
25+
DEV02 verifiziert (MERGE-Logik gegen eine Mock-Tabelle getestet: Aenderungen korrekt
26+
uebernommen, neue Zeilen eingefuegt, nicht in der Primary-Liste enthaltene Zeilen unangetastet
27+
gelassen, Escaping von Anfuehrungszeichen in `Reason` korrekt). Echte AlwaysOn-Propagierung
28+
selbst ist auf DEV02 nicht End-to-End testbar (keine AG dort vorhanden).
29+
330
## [1.9.2.0] — 2026-07-03
431

532
### Erweiterung

Public/New-sqmOlaUsrDbBackupJob.ps1

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -905,8 +905,12 @@ END
905905
if (-not $ContinueOnError) { throw }
906906
}
907907

908-
# AlwaysOn-Propagierung: erfolgreich erstellte Jobs auch auf Secondary-Repliken anlegen
909-
if (-not $SkipAlwaysOnPropagation -and $jobDefinitions -and ($results | Where-Object { $_.JobStatus -eq 'Created' }))
908+
# AlwaysOn-Propagierung: Jobs auch auf Secondary-Repliken anlegen/aktualisieren.
909+
# Nicht nur bei 'Created' ausloesen - sonst propagiert ein spaeterer -Update-Lauf (JobStatus
910+
# 'Updated') oder ein erneuter Lauf ohne Aenderung ('AlreadyExists') NIE auf die Secondaries,
911+
# obwohl New-sqmOlaUsrDbBackupJob dort idempotent per -Update erneut aufgerufen wird - Ursache
912+
# fuer fehlende/veraltete Jobs auf Secondaries nach dem allerersten Lauf.
913+
if (-not $SkipAlwaysOnPropagation -and $jobDefinitions -and ($results | Where-Object { $_.JobStatus -in @('Created', 'Updated', 'AlreadyExists') }))
910914
{
911915
try
912916
{

Public/Sync-sqmBackupExcludeTable.ps1

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,17 @@ WHERE r.replica_server_name <> @@SERVERNAME
413413
"@
414414
$secondaries = Invoke-DbaQuery @connParams -Database master -Query $replicaQuery -ErrorAction SilentlyContinue
415415

416+
# Aktueller, endgueltiger Stand der PRIMARY nach allen obigen Aenderungen - wird unten
417+
# per MERGE an jede Secondary GEPUSHT (nicht nur strukturell abgeglichen). Der
418+
# rekursive Sync-sqmBackupExcludeTable-Aufruf allein erkennt auf der Secondary nur
419+
# NEUE/geloeschte Datenbanken selbst, uebernimmt aber NIE die vom Admin ueber
420+
# Show-sqmBackupExcludeForm gesetzten IsActive/Reason-Werte der Primary - das war die
421+
# Ursache dafuer, dass Aenderungen an der Exclude-Liste nie auf Secondaries ankamen.
422+
$primaryRows = if ($secondaries)
423+
{
424+
Invoke-DbaQuery @connParams -Database master -Query "SELECT DatabaseName, Reason, IsActive FROM master.dbo.sqm_BackupExclude" -ErrorAction Stop
425+
}
426+
416427
foreach ($sec in $secondaries)
417428
{
418429
$secName = $sec.replica_server_name
@@ -428,14 +439,37 @@ WHERE r.replica_server_name <> @@SERVERNAME
428439

429440
Sync-sqmBackupExcludeTable @secParams -ErrorAction Stop | Out-Null
430441

442+
if ($primaryRows)
443+
{
444+
$secConnParams = @{ SqlInstance = $secName }
445+
if ($SqlCredential) { $secConnParams['SqlCredential'] = $SqlCredential }
446+
447+
$valuesSql = ($primaryRows | ForEach-Object {
448+
$reasonSql = if ([string]::IsNullOrEmpty($_.Reason)) { 'NULL' } else { "N'$($_.Reason.Replace("'", "''"))'" }
449+
"(N'$($_.DatabaseName.Replace("'", "''"))', $reasonSql, $([int][bool]$_.IsActive))"
450+
}) -join ', '
451+
452+
$mergeSql = @"
453+
MERGE master.dbo.sqm_BackupExclude AS tgt
454+
USING (VALUES $valuesSql) AS src (DatabaseName, Reason, IsActive)
455+
ON tgt.DatabaseName = src.DatabaseName
456+
WHEN MATCHED AND (tgt.IsActive <> src.IsActive OR ISNULL(tgt.Reason, N'') <> ISNULL(src.Reason, N'')) THEN
457+
UPDATE SET IsActive = src.IsActive, Reason = src.Reason
458+
WHEN NOT MATCHED BY TARGET THEN
459+
INSERT (DatabaseName, Reason, IsActive, IsOrphaned) VALUES (src.DatabaseName, src.Reason, src.IsActive, 0);
460+
"@
461+
Invoke-DbaQuery @secConnParams -Database master -Query $mergeSql -ErrorAction Stop
462+
Invoke-sqmLogging -Message "AlwaysOn: IsActive/Reason-Werte der Primary auf '$secName' uebertragen ($($primaryRows.Count) Zeile(n))." -FunctionName $functionName -Level "INFO"
463+
}
464+
431465
Invoke-sqmLogging -Message "AlwaysOn: Secondary '$secName' erfolgreich synchronisiert." -FunctionName $functionName -Level "INFO"
432466
$results.Add([PSCustomObject]@{
433467
SqlInstance = $secName
434468
DatabaseName = 'N/A'
435469
Action = 'AlwaysOnPropagated'
436470
IsActive = $null
437471
IsOrphaned = $null
438-
Message = "AlwaysOn Secondary '$secName' synchronisiert."
472+
Message = "AlwaysOn Secondary '$secName' synchronisiert (inkl. IsActive/Reason-Werte)."
439473
})
440474
}
441475
catch

sqmSQLTool.psd1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
RootModule = 'sqmSQLTool.psm1'
1818

1919
# Version number of this module.
20-
ModuleVersion = '1.9.2.0'
20+
ModuleVersion = '1.9.3.0'
2121

2222
# ID used to uniquely identify this module
2323
GUID = 'c4b10ba2-aee2-4d8d-ad86-a6e97c346ba6'

0 commit comments

Comments
 (0)