USE [dba]
GO

/****** Object:  StoredProcedure [dbo].[start_snapshot]    Script Date: 15.04.2025 10:24:03 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO


/*
start_snapshot

SP used to start the associated "repl-snapshot" job from a published database.

Variable @published_db
    If null, starts the snapshot job of all published dbs
    If not null, must contain the name of a db that is published and will start the snapshot job of that db only

15.04.2025	TSC	Adapted to avoid trying to start several time the same job
*/
CREATE OR ALTER   PROCEDURE [dbo].[start_snapshot]
  @published_db VARCHAR(500),
  @debug BIT = 0
AS
BEGIN
  SET NOCOUNT ON;
  SET XACT_ABORT ON;

  DECLARE @jobs TABLE (publisher_db sysname NOT NULL,
                       agent_name sysname NOT NULL,
                       job_name sysname NOT NULL,
                       start_execution_date DATETIME NULL,
                       stop_execution_date DATETIME NULL,
                       next_scheduled_run_date DATETIME NULL,
                       current_job_status VARCHAR(50) NOT NULL,
                       start_job_cmd AS 'exec msdb.dbo.sp_start_job @job_name=''' + job_name + ''';');
  DECLARE @cmd NVARCHAR(MAX) = N'';

  INSERT INTO @jobs ([publisher_db],
                     [agent_name],
                     [job_name],
                     [start_execution_date],
                     [stop_execution_date],
                     [next_scheduled_run_date],
                     [current_job_status])
  SELECT distinct   
              [a].[publisher_db],
              [a].[name] AS [agent_name],
              [s].[name] AS [job_name],
              [ac].[start_execution_date],
              [ac].[stop_execution_date],
              [ac].[next_scheduled_run_date],
              CASE
                   WHEN [ac].[start_execution_date] IS NOT NULL
                    AND [ac].[stop_execution_date] IS NULL THEN 'running'
                   WHEN [ac].[start_execution_date] IS NOT NULL
                    AND [ac].[stop_execution_date] IS NOT NULL THEN 'finished'
                   WHEN [ac].[start_execution_date] IS NULL
                    AND [ac].[stop_execution_date] IS NULL THEN 'never started'
                   ELSE 'unknown' END AS current_job_status
    FROM      [distribution].dbo.[MSsnapshot_agents] a
    JOIN      [msdb].[dbo].[sysjobs] s
      ON [s].[job_id]  = [a].[job_id]
    LEFT JOIN ( SELECT TOP 1 --last execution, if ever there was one
					   [ja].[job_id],
                       [ja].[start_execution_date],
                       [ja].[stop_execution_date],
                       [ja].[next_scheduled_run_date]
                  FROM [msdb].[dbo].[sysjobactivity] ja
				  ORDER BY [start_execution_date] DESC
				  ) ac
      ON [ac].[job_id] = [s].[job_id]
   WHERE      [a].[publisher_db] = COALESCE(@published_db, [a].[publisher_db])
   ORDER BY [a].[publisher_db];

  IF NOT EXISTS (SELECT 1 FROM @jobs)
  BEGIN
    RAISERROR('Database %s is not existing or not published in a replication', 16, 5, @published_db);
    RETURN;
  END;

  if @debug=1
  begin
	select *
	from @jobs
  end

  SELECT @cmd = @cmd + j.start_job_cmd
    FROM @jobs j
   WHERE [j].[current_job_status] <> 'running';

  IF @debug = 1
  BEGIN
    PRINT @cmd;
  END;
  ELSE
  BEGIN
    EXEC (@cmd);
    
    --give a couple seconds for the agent(s) to start
    WAITFOR DELAY '00:00:15';

    --do not exit this proc until the last snapshot job started has finished
    WHILE EXISTS(
        --return something while a snapshot job is running
        SELECT 1
        FROM msdb.dbo.[sysjobs] j
            JOIN msdb.dbo.[sysjobactivity] ja ON [j].[job_id] = [ja].[job_id]
            JOIN [distribution].dbo.[MSsnapshot_agents] a ON a.[job_id] = j.[job_id]
        WHERE a.[publisher_db] = COALESCE(@published_db, a.[publisher_db])
        AND [ja].[start_execution_date] IS NOT NULL 
        AND [ja].[stop_execution_date] IS NULL 
    )
    BEGIN
        WAITFOR DELAY '00:00:05';
        RAISERROR('waiting for snapshot job(s) to finish',0,0) WITH NOWAIT;
    END
  END;
END;

GO

