Reputation: 453
I'm trying to get the status of my jobs in MS SQL Server, the aim is to create an alert in our remote monitoring software if any of the enabled jobs have errored.
Currently I'm using the sys.xp_sqlagent_enum_jobs stored procedure however that seems to show both enabled and disabled jobs, so I tried using the msdb.dbo.sp_help_job, this is exactly what I need but without using the OPENQUERY parameter (which is disabled on the servers) I can't query or capture the results because of the nesting error, I got the same with sp_get_composite_job_info.
So I'm starting to run out of ideas does anyone know of a way to capture this information for query or to store in a able for query later.
I'll include my current code in case it is useful for anyone, it works well returning the number of failed jobs, but if you have a failed job that is disabled this also shows up.
objRecordSet.Open _
"SET NOCOUNT ON " & _
"DECLARE @MaxLength INT " & _
"SET @MaxLength = 50 " & _
"DECLARE @xp_results TABLE ( job_id uniqueidentifier NOT NULL, " & _
"last_run_date nvarchar (20) NOT NULL, " & _
"last_run_time nvarchar (20) NOT NULL, " & _
"next_run_date nvarchar (20) NOT NULL, " & _
"next_run_time nvarchar (20) NOT NULL, " & _
"next_run_schedule_id INT NOT NULL, " & _
"requested_to_run INT NOT NULL, " & _
"request_source INT NOT NULL, " & _
"request_source_id sysname " & _
"COLLATE database_default NULL, " & _
"running INT NOT NULL, " & _
"current_step INT NOT NULL, " & _
"current_retry_attempt INT NOT NULL, " & _
"job_state INT NOT NULL " & _
")" & _
"DECLARE @job_owner sysname " & _
"DECLARE @is_sysadmin INT " & _
"SET @is_sysadmin = isnull (is_srvrolemember ('sysadmin'), 0) " & _
"SET @job_owner = suser_sname () " & _
"INSERT INTO @xp_results EXECUTE sys.xp_sqlagent_enum_jobs @is_sysadmin, @job_owner " & _
"UPDATE @xp_results SET last_run_time = right ('000000' + last_run_time, 6), next_run_time = right ('000000' + next_run_time, 6) " & _
"SELECT count(*) as cnt FROM @xp_results x LEFT JOIN msdb.dbo.sysjobs j ON x.job_id = j.job_id LEFT OUTER JOIN msdb.dbo.syscategories c " & _
"ON j.category_id = c.category_id LEFT OUTER JOIN msdb.dbo.sysjobhistory h ON x.job_id = h.job_id " & _
"AND x.last_run_date = h.run_date AND x.last_run_time = h.run_time AND h.step_id = 0 where h.run_status = 0 ", _
objConnection, adOpenStatic, adLockOptimistic
message = message & "JOBCHECK#" & objRecordSet("cnt") & vbNewLine
Upvotes: 1
Views: 2713
Reputation: 453
Many thanks using help from djangojazz, I was able to do what I wanted:
use msdb;
Select count(*) as cnt
from sysjobs j (nolock)
join sysjobhistory jh (nolock) on j.job_id = jh.job_id
and instance_id = (
select MAX(instance_id)
from sysjobhistory (nolock)
where job_id = j.job_id
)
and j.enabled = 1
and jh.run_status = 0
Upvotes: 0
Reputation: 13232
Not that hard. Keep in mind SQL Server keeps meta data info at all times on what detail is being done to the server actively. I would do this to find failures in that you could create a proc or function, call it by date range. I gave an example of just the query though for the time being:
use msdb;
declare
@Start int = cast( convert(varchar,
dateadd(ww, datediff(ww, 0, getdate())-1,0) -- last week starting
, 112) as int)
, @End int = cast( convert(varchar,
getdate() -- current datetime
, 112) as int)
;
Select
j.name
, j.description
, cast( cast(jh.run_date as varchar) + ' ' + left(jh.run_time, 2) + ':' + substring( cast(jh.run_time as varchar), 3, 2) as datetime) as TimeRan
, jh.message
, jh.step_id
, jh.step_name
from sysjobs j (nolock)
join sysjobhistory jh (nolock) on j.job_id = jh.job_id
and jh.run_date between @Start and @End
and jh.run_status = 0 -- 0 is failure
Upvotes: 3