Nella cassetta degli attrezzi di un sistemista che si rispetti non può mancare Powershell. Io personalmente lo adoro e mi permette di automatizzare molti task sistemistici.
Qui sotto riporto un piccolo esempio per integrare uno script Powershell in un job SQL:
$ErrorActionPreference = "Stop"
try{
QUI IL MIO CODICE O LA CHIAMATA AL MIO PS1
}
catch{
Throw
}
Impostato in questa maniera, siamo in grado di intercettare nel job history di SQL le eventuali eccezioni ed errori del nostro script, cosa molto utile se lo si schedula in orario non lavorativo, con alerting automatico in caso di abend (Abnormal End)
Quella del cluster database di tipo AAG (Always-on Availability Group) è una delle configurazioni più resilienti di SQL e tramite una configurazione a nodo 1+N che se bilanciata bene permette una grossa resilienza ed un importante uptime.
Introduzione
Nell’AAG, uno dei nodi è sempre il primario, i “+N” (che potrebbe essere uno o molteplici) rimangono in standby con una replica puntuale dei DB. Una delle caratteristiche più interessanti della configurazione AAG è il failover automatico, che consiste nel cambio ruolo automatico a fronte di un problema tecnico. In questo scenario potrebbe essere necessario attivare dei servizi ancillari alla macchina, come ad esempio uno schedulatore esterno (es IWS), uno strumento di file transfer o un qualsiasi agent.
Esempio di TSQL per Avviare o Arrestare dinamicamente un servizio in base al nodo in cui sta girando l’istanza
di seguito, un piccolo POC con un esempio di TSQL per avviare o disabilitare un servizio a fronte di un cambio ruolo di SQL:
DECLARE @primreplica VARCHAR(100);
DECLARE @ServiceName VARCHAR(128) = 'NOMESERVIZIO';
DECLARE @Status VARCHAR(MAX);
DECLARE @ServicesStatus TABLE
(
Status VARCHAR(50)
);
SELECT @primreplica = s.primary_replica
FROM sys.dm_hadr_availability_group_states s
JOIN sys.availability_groups ag
ON ag.group_id = s.group_id;
-- se dove sto girando è primario
IF UPPER(@primreplica) = UPPER(@@SERVERNAME)
BEGIN
INSERT @ServicesStatus
EXEC xp_servicecontrol N'QUERYSTATE', @ServiceName;
SELECT @Status = Status
FROM @ServicesStatus;
--select @Status
IF @Status <> 'Running.'
BEGIN
EXEC xp_servicecontrol N'Start', @ServiceName;
END;
END;
ELSE
BEGIN
INSERT @ServicesStatus
EXEC xp_servicecontrol N'QUERYSTATE', @ServiceName;
SELECT @Status = Status
FROM @ServicesStatus;
--select @Status
IF @Status = 'Running.'
BEGIN
EXEC xp_servicecontrol N'Stop', @ServiceName;
END;
END;
Personalmente, l’ho schedulato in un job SQL sempre attivo su tutti i nodi (lo stesso JOB contiene lo statement per abilitare o disabilitare i JOB SQL).
Andiamo un poco più in drill-down: Tramite la select di seguito riportata, stabilisco se sto girando sulla replica primaria o sul secondario, andando a confrontare il nome del server su cui sta girando l’istanza (tramite la funzione SQL @@SERVERNAME) ed il nome della replica primaria sulle tabelle di sistema che regolano l’AAG:
SELECT @primreplica = s.primary_replica
FROM sys.dm_hadr_availability_group_states s
JOIN sys.availability_groups ag
ON ag.group_id = s.group_id;
-- se dove sto girando è primario
IF UPPER(@primreplica) = UPPER(@@SERVERNAME)
Con un semplice ciclo IF/ELSE tramite una tabella di appoggio e la StoreProcedure EXEC xp_servicecontrol determino se il servizio sta girando o meno ed in base alla risposta ed al server, avvio o disabilito il servizio:
INSERT @ServicesStatus
EXEC xp_servicecontrol N'QUERYSTATE', @ServiceName;
SELECT @Status = Status
FROM @ServicesStatus;
--select @Status
IF @Status <> 'Running.'
BEGIN
EXEC xp_servicecontrol N'Start', @ServiceName;
END;