Hacer que un trabajo finalice si no se ejecuta en la réplica principal
Para este caso, cada trabajo en ambos servidores necesita cualquiera de los siguientes dos fragmentos de código como el Paso 1:
Verificar por nombre de grupo:
IF master.dbo.svf_AgReplicaState('my_group_name')=0
raiserror ('This is not the primary replica.',2,1)
Verificar por nombre de base de datos:
IF master.dbo.svf_AgReplicaState('my_db_name')=0
raiserror ('This is not the primary replica.',2,1)
Sin embargo, si usa este segundo, tenga cuidado con las bases de datos del sistema; por definición, no pueden ser parte de ningún grupo de disponibilidad, por lo que siempre fallará para ellos.
Ambos funcionan de forma inmediata para los usuarios administradores. Para los usuarios que no son administradores, debe agregar permisos adicionales, uno de ellos sugerido aquí :
GRANT VIEW SERVER STATE TO [user];
GRANT VIEW ANY DEFINITION TO [user];
Si configura la acción de falla para Salir del informe de trabajo exitoso en este primer paso, no obtendrá el registro de trabajo lleno de feos signos de cruz roja, para el trabajo principal se convertirán en señales de advertencia amarillas.
Desde nuestra experiencia, esto no es ideal. Al principio adoptamos este enfoque, pero rápidamente perdimos la noción de encontrar trabajos que realmente tuvieran un problema, porque todos los trabajos de réplica secundaria saturaban el registro de trabajos con mensajes de advertencia.
Lo que luego buscamos es:
Trabajos proxy
Si adopta este concepto, en realidad necesitará crear dos trabajos por tarea que desee realizar. El primero es el "trabajo proxy" que comprueba si se está ejecutando en la réplica principal. Si es así, comienza el "trabajo de trabajo", de lo contrario, finaliza con gracia sin saturar el registro con mensajes de advertencia o error.
Si bien personalmente no me gusta la idea de tener dos trabajos por tarea en cada servidor, creo que es definitivamente más fácil de mantener, y no tiene que establecer la acción de falla del paso para Salir del informe de éxito , lo cual es un poco torpe.
Para los trabajos, adoptamos un esquema de nombres. El trabajo proxy solo se llama {put jobname here}
. El trabajo del trabajador se llama {put jobname here} worker
. Esto hace posible automatizar el inicio del trabajo del trabajador desde el proxy. Para hacerlo, agregué el siguiente procedimiento a ambos dbs maestros:
CREATE procedure [dbo].[procStartWorkerJob](@jobId uniqueidentifier, @availabilityGroup sysname, @postfix sysname = ' worker') as
declare @name sysname
if dbo.svf_AgReplicaState(@availabilityGroup)=0
print 'This is not the primary replica.'
else begin
SELECT @name = name FROM msdb.dbo.sysjobs where job_id = @jobId
set @name = @name + @postfix
if exists(select name from msdb.dbo.sysjobs where name = @name)
exec msdb.dbo.sp_start_job @name
else begin
set @name = 'Job '''+@name+''' not found.'
raiserror (@name ,2,1)
end
end
GO
Esto utiliza la svf_AgReplicaState
función que se muestra arriba, puede cambiarla fácilmente para verificar usando el nombre de la base de datos llamando a la otra función.
Desde el único paso del trabajo proxy, lo llamas así:
exec procStartWorkerJob $(ESCAPE_NONE(JOBID)), '{my_group_name}'
Esto utiliza tokens como se muestra aquí y aquí para obtener la identificación del trabajo actual. El procedimiento luego obtiene el nombre del trabajo actual de msdb, lo agrega worker
y comienza a usar el trabajo del trabajador sp_start_job
.
Si bien esto aún no es ideal, mantiene los registros de trabajo más ordenados y fáciles de mantener que la opción anterior. Además, siempre puede ejecutar el trabajo proxy con un usuario sysadmin, por lo que no es necesario agregar permisos adicionales.