how to know status of currently running jobs

Sql ServerSql Server-2008TsqlSql Agent

Sql Server Problem Overview


I need to know if a given Job is currently running on Ms SQL 2008 server. So as to not to invoke same job again that may lead to concurrency issues.

Sql Server Solutions


Solution 1 - Sql Server

It looks like you can use msdb.dbo.sysjobactivity, checking for a record with a non-null start_execution_date and a null stop_execution_date, meaning the job was started, but has not yet completed.

This would give you currently running jobs:

SELECT sj.name
   , sja.*
FROM msdb.dbo.sysjobactivity AS sja
INNER JOIN msdb.dbo.sysjobs AS sj ON sja.job_id = sj.job_id
WHERE sja.start_execution_date IS NOT NULL
   AND sja.stop_execution_date IS NULL

Solution 2 - Sql Server

I found a better answer by Kenneth Fisher. The following query returns only currently running jobs:

SELECT
    ja.job_id,
    j.name AS job_name,
    ja.start_execution_date,      
    ISNULL(last_executed_step_id,0)+1 AS current_executed_step_id,
    Js.step_name
FROM msdb.dbo.sysjobactivity ja 
LEFT JOIN msdb.dbo.sysjobhistory jh ON ja.job_history_id = jh.instance_id
JOIN msdb.dbo.sysjobs j ON ja.job_id = j.job_id
JOIN msdb.dbo.sysjobsteps js
    ON ja.job_id = js.job_id
    AND ISNULL(ja.last_executed_step_id,0)+1 = js.step_id
WHERE
  ja.session_id = (
    SELECT TOP 1 session_id FROM msdb.dbo.syssessions ORDER BY agent_start_date DESC
  )
AND start_execution_date is not null
AND stop_execution_date is null;

You can get more information about a job by adding more columns from msdb.dbo.sysjobactivity table in select clause.

Solution 3 - Sql Server

EXEC msdb.dbo.sp_help_job @Job_name = 'Your Job Name'

check field execution_status

0 - Returns only those jobs that are not idle or suspended.
1 - Executing.
2 - Waiting for thread.
3 - Between retries.
4 - Idle.
5 - Suspended.
7 - Performing completion actions.

If you need the result of execution, check the field last_run_outcome

0 = Failed
1 = Succeeded
3 = Canceled
5 = Unknown

https://msdn.microsoft.com/en-us/library/ms186722.aspx

Solution 4 - Sql Server

Given a job (I assume you know its name) you can use:

EXEC msdb.dbo.sp_help_job @Job_name = 'Your Job Name'

as suggested in MSDN Job Help Procedure. It returns a lot of informations about the job (owner, server, status and so on).

Solution 5 - Sql Server

This query will give you the exact output for current running jobs. This will also shows the duration of running job in minutes.

   WITH
	CTE_Sysession (AgentStartDate)
	AS 
	(
		SELECT MAX(AGENT_START_DATE) AS AgentStartDate FROM MSDB.DBO.SYSSESSIONS
	)	
SELECT sjob.name AS JobName
		,CASE 
			WHEN SJOB.enabled = 1 THEN 'Enabled'
			WHEN sjob.enabled = 0 THEN 'Disabled'
			END AS JobEnabled
		,sjob.description AS JobDescription
		,CASE 
			WHEN ACT.start_execution_date IS NOT NULL AND ACT.stop_execution_date IS NULL  THEN 'Running'
			WHEN ACT.start_execution_date IS NOT NULL AND ACT.stop_execution_date IS NOT NULL AND HIST.run_status = 1 THEN 'Stopped'
			WHEN HIST.run_status = 0 THEN 'Failed'
			WHEN HIST.run_status = 3 THEN 'Canceled'
		END AS JobActivity
		,DATEDIFF(MINUTE,act.start_execution_date, GETDATE()) DurationMin
		,hist.run_date AS JobRunDate
		,run_DURATION/10000 AS Hours
		,(run_DURATION%10000)/100 AS Minutes 
		,(run_DURATION%10000)%100 AS Seconds
		,hist.run_time AS JobRunTime 
		,hist.run_duration AS JobRunDuration
		,'tulsql11\dba' AS JobServer
		,act.start_execution_date AS JobStartDate
		,act.last_executed_step_id AS JobLastExecutedStep
		,act.last_executed_step_date AS JobExecutedStepDate
		,act.stop_execution_date AS JobStopDate
		,act.next_scheduled_run_date AS JobNextRunDate
		,sjob.date_created AS JobCreated
		,sjob.date_modified AS JobModified		
			FROM MSDB.DBO.syssessions AS SYS1
		INNER JOIN CTE_Sysession AS SYS2 ON SYS2.AgentStartDate = SYS1.agent_start_date
		JOIN  msdb.dbo.sysjobactivity act ON act.session_id = SYS1.session_id
	    JOIN msdb.dbo.sysjobs sjob ON sjob.job_id = act.job_id
		LEFT JOIN  msdb.dbo.sysjobhistory hist ON hist.job_id = act.job_id AND hist.instance_id = act.job_history_id
		WHERE ACT.start_execution_date IS NOT NULL AND ACT.stop_execution_date IS NULL
		ORDER BY ACT.start_execution_date DESC

Solution 6 - Sql Server

EXECUTE master.dbo.xp_sqlagent_enum_jobs 1,''

Notice the column Running, obviously 1 means that it is currently running, and [Current Step]. This returns job_id to you, so you'll need to look these up, e.g.:

SELECT top 100 *
 FROM	msdb..sysjobs
 WHERE	job_id IN (0x9DAD1B38EB345D449EAFA5C5BFDC0E45, 0xC00A0A67D109B14897DD3DFD25A50B80, 0xC92C66C66E391345AE7E731BFA68C668)

Solution 7 - Sql Server

DECLARE @StepCount INT
SELECT @StepCount = COUNT(1)
FROM msdb.dbo.sysjobsteps
WHERE job_id = '0523333-5C24-1526-8391-AA84749345666' --JobID


SELECT
         [JobName]
        ,[JobStepID]
        ,[JobStepName]
        ,[JobStepStatus]
        ,[RunDateTime]
        ,[RunDuration]
    FROM
    (
        SELECT 
                j.[name] AS [JobName]
            ,Jh.[step_id] AS [JobStepID]
            ,jh.[step_name] AS [JobStepName]
            ,CASE 
                WHEN jh.[run_status] = 0 THEN 'Failed'
                WHEN jh.[run_status] = 1 THEN 'Succeeded'
                WHEN jh.[run_status] = 2 THEN 'Retry (step only)'
                WHEN jh.[run_status] = 3 THEN 'Canceled'
                WHEN jh.[run_status] = 4 THEN 'In-progress message'
                WHEN jh.[run_status] = 5 THEN 'Unknown'
                ELSE 'N/A'
                END AS [JobStepStatus]
            ,msdb.dbo.agent_datetime(run_date, run_time) AS [RunDateTime]
            ,CAST(jh.[run_duration]/10000 AS VARCHAR)  + ':' + CAST(jh.[run_duration]/100%100 AS VARCHAR) + ':' + CAST(jh.[run_duration]%100 AS VARCHAR) AS [RunDuration]
            ,ROW_NUMBER() OVER 
            (
                PARTITION BY jh.[run_date]
                ORDER BY jh.[run_date] DESC, jh.[run_time] DESC
            ) AS [RowNumber]
        FROM 
            msdb.[dbo].[sysjobhistory] jh
            INNER JOIN msdb.[dbo].[sysjobs] j
                ON jh.[job_id] = j.[job_id]
        WHERE 
            j.[name] = 'ProcessCubes' --Job Name
            AND jh.[step_id] > 0
            AND CAST(RTRIM(run_date) AS DATE) = CAST(GETDATE() AS DATE) --Current Date
    ) A
    WHERE 
        [RowNumber] <= @StepCount
        AND [JobStepStatus] = 'Failed'

Solution 8 - Sql Server

We've found and have been using this code for a good solution. This code will start a job, and monitor it, killing the job automatically if it exceeds a time limit.

/****************************************************************
--This SQL will take a list of SQL Agent jobs (names must match),
--start them so they're all running together, and then
--monitor them, not quitting until all jobs have completed.
--
--In essence, it's an SQL "watchdog" loop to start and monitor SQL Agent Jobs
--
--Code from http://cc.davelozinski.com/code/sql-watchdog-loop-start-monitor-sql-agent-jobs
--
****************************************************************/
SET NOCOUNT ON 

-------- BEGIN ITEMS THAT NEED TO BE CONFIGURED --------

--The amount of time to wait before checking again 
--to see if the jobs are still running.
--Should be in hh:mm:ss format. 
DECLARE @WaitDelay VARCHAR(8) = '00:00:20'

--Job timeout. Eg, if the jobs are running longer than this, kill them.
DECLARE @TimeoutMinutes INT = 240

DECLARE @JobsToRunTable TABLE
(
	JobName NVARCHAR(128) NOT NULL,
	JobID UNIQUEIDENTIFIER NULL,
	Running INT NULL
)

--Insert the names of the SQL jobs here. Last two values should always be NULL at this point.
--Names need to match exactly, so best to copy/paste from the SQL Server Agent job name.
INSERT INTO @JobsToRunTable (JobName, JobID, Running) VALUES ('NameOfFirstSQLAgentJobToRun',NULL,NULL)
INSERT INTO @JobsToRunTable (JobName, JobID, Running) VALUES ('NameOfSecondSQLAgentJobToRun',NULL,NULL)
INSERT INTO @JobsToRunTable (JobName, JobID, Running) VALUES ('NameOfXSQLAgentJobToRun',NULL,NULL)

-------- NOTHING FROM HERE DOWN SHOULD NEED TO BE CONFIGURED --------

DECLARE @ExecutionStatusTable TABLE
(
	JobID UNIQUEIDENTIFIER PRIMARY KEY, -- Job ID which will be a guid
	LastRunDate INT, LastRunTime INT, -- Last run date and time
	NextRunDate INT, NextRunTime INT, -- Next run date and time
	NextRunScheduleID INT, -- an internal schedule id
	RequestedToRun INT, RequestSource INT, RequestSourceID VARCHAR(128),
	Running INT,	-- 0 or 1, 1 means the job is executing
	CurrentStep INT, -- which step is running
	CurrentRetryAttempt INT, -- retry attempt
	JobState INT -- 0 = Not idle or suspended, 1 = Executing, 2 = Waiting For Thread,
                     -- 3 = Between Retries, 4 = Idle, 5 = Suspended, 
                     -- 6 = WaitingForStepToFinish, 7 = PerformingCompletionActions
)

DECLARE @JobNameToRun NVARCHAR(128) = NULL
DECLARE @IsJobRunning BIT = 1
DECLARE @AreJobsRunning BIT = 1
DECLARE @job_owner sysname = SUSER_SNAME()
DECLARE @JobID UNIQUEIDENTIFIER = null
DECLARE @StartDateTime DATETIME = GETDATE()
DECLARE @CurrentDateTime DATETIME = null
DECLARE @ExecutionStatus INT = 0
DECLARE @MaxTimeExceeded BIT = 0

--Loop through and start every job
DECLARE dbCursor CURSOR FOR SELECT JobName FROM @JobsToRunTable
OPEN dbCursor FETCH NEXT FROM dbCursor INTO @JobNameToRun
WHILE @@FETCH_STATUS = 0
BEGIN
	EXEC [msdb].[dbo].sp_start_job @JobNameToRun
	FETCH NEXT FROM dbCursor INTO @JobNameToRun
END
CLOSE dbCursor
DEALLOCATE dbCursor

print '*****************************************************************'
print 'Jobs started. ' + CAST(@StartDateTime as varchar)
print '*****************************************************************'

--Debug (if needed)
--SELECT * FROM @JobsToRunTable

WHILE 1=1 AND @AreJobsRunning = 1
BEGIN

	--This has to be first with the delay to make sure the jobs
	--have time to actually start up and are recognized as 'running'
	WAITFOR DELAY @WaitDelay 

	--Reset for each loop iteration
	SET @AreJobsRunning = 0

	--Get the currently executing jobs by our user name
	INSERT INTO @ExecutionStatusTable
	EXECUTE [master].[dbo].xp_sqlagent_enum_jobs 1, @job_owner

	--Debug (if needed)
	--SELECT 'ExecutionStatusTable', * FROM @ExecutionStatusTable

	--select every job to see if it's running
	DECLARE dbCursor CURSOR FOR 
		SELECT x.[Running], x.[JobID], sj.name 
		FROM @ExecutionStatusTable x 
		INNER JOIN [msdb].[dbo].sysjobs sj ON sj.job_id = x.JobID
		INNER JOIN @JobsToRunTable jtr on sj.name = jtr.JobName
	OPEN dbCursor FETCH NEXT FROM dbCursor INTO @IsJobRunning, @JobID, @JobNameToRun

	--Debug (if needed)
	--SELECT x.[Running], x.[JobID], sj.name 
	--	FROM @ExecutionStatusTable x 
	--	INNER JOIN msdb.dbo.sysjobs sj ON sj.job_id = x.JobID
	--	INNER JOIN @JobsToRunTable jtr on sj.name = jtr.JobName

	WHILE @@FETCH_STATUS = 0
	BEGIN
		--bitwise operation to see if the loop should continue
		SET @AreJobsRunning = @AreJobsRunning | @IsJobRunning

		UPDATE @JobsToRunTable
		SET Running = @IsJobRunning, JobID = @JobID
		WHERE JobName = @JobNameToRun

		--Debug (if needed)
		--SELECT 'JobsToRun', * FROM @JobsToRunTable
		
		SET @CurrentDateTime=GETDATE()

		IF @IsJobRunning = 1
		BEGIN -- Job is running or finishing (not idle)

			IF DATEDIFF(mi, @StartDateTime, @CurrentDateTime) > @TimeoutMinutes
			BEGIN     
				print '*****************************************************************'
				print @JobNameToRun + ' exceeded timeout limit of ' + @TimeoutMinutes + ' minutes. Stopping.'
				--Stop the job
				EXEC [msdb].[dbo].sp_stop_job @job_name = @JobNameToRun
			END
			ELSE
			BEGIN
				print @JobNameToRun + ' running for ' + CONVERT(VARCHAR(25),DATEDIFF(mi, @StartDateTime, @CurrentDateTime)) + ' minute(s).'
			END
		END

		IF @IsJobRunning = 0 
		BEGIN
			--Job isn't running
			print '*****************************************************************'
			print @JobNameToRun + ' completed or did not run. ' + CAST(@CurrentDateTime as VARCHAR)
		END

		FETCH NEXT FROM dbCursor INTO @IsJobRunning, @JobID, @JobNameToRun

	END -- WHILE @@FETCH_STATUS = 0
	CLOSE dbCursor
	DEALLOCATE dbCursor

	--Clear out the table for the next loop iteration
	DELETE FROM @ExecutionStatusTable

	print '*****************************************************************'

END -- WHILE 1=1 AND @AreJobsRunning = 1

SET @CurrentDateTime = GETDATE()
print 'Finished at ' + CAST(@CurrentDateTime as varchar)
print CONVERT(VARCHAR(25),DATEDIFF(mi, @StartDateTime, @CurrentDateTime)) + ' minutes total run time.'

Solution 9 - Sql Server

You can query the table msdb.dbo.sysjobactivity to determine if the job is currently running.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTonyPView Question on Stackoverflow
Solution 1 - Sql ServerAdam WengerView Answer on Stackoverflow
Solution 2 - Sql ServerNirajView Answer on Stackoverflow
Solution 3 - Sql ServerNicholas GiudiceView Answer on Stackoverflow
Solution 4 - Sql ServerFrancesco De LisiView Answer on Stackoverflow
Solution 5 - Sql ServerBasant MishraView Answer on Stackoverflow
Solution 6 - Sql ServerDavid RodeckerView Answer on Stackoverflow
Solution 7 - Sql ServerRajiv SinghView Answer on Stackoverflow
Solution 8 - Sql Serveruser3810913View Answer on Stackoverflow
Solution 9 - Sql ServerSonamView Answer on Stackoverflow