如何准确检测SQL Server作业是否正在运行并处理已在运行的作业?

时间:2011-05-02 19:02:29

标签: sql-server tsql sql-server-agent sql-agent-job

我目前正在使用这样的代码来检测SQL服务器作业是否正在运行。 (这是SQL Server 2005,所有SP的)

return (select isnull(  
(select top 1 CASE 
    WHEN current_execution_status = 4 THEN 0
    ELSE 1
    END
from openquery(devtestvm, 'EXEC msdb.dbo.sp_help_job')
where current_execution_status = 4 and
    name = 'WQCheckQueueJob' + cast(@Index as varchar(10))
), 1)
)

那里没有问题,一般来说,它运作得很好。

但....(总是一个但是)

有时候,我会调用它,取回“工作未运行”的结果,此时我会尝试通过

开始工作
exec msdb.dbo.sp_start_job @JobName

并且SQL将返回“SQLAgent拒绝启动该作业,因为它已经有待处理的请求”。

确定。也不是问题。可以想象,在此代码启动之前,可以启动目标作业的一个小窗口,但在检查它是否已启动之后。但是,我可以将它包装在try catch中,然后忽略错误,对吧?

begin try
if dbo.WQIsQueueJobActive(@index) = 0 begin
    exec msdb.dbo.sp_start_job @JobName
    break
end         
end try begin catch
    -- nothing here
end catch

这是问题所在。

10次中有9次,这很好用。 SQL代理将引发错误,它被捕获,并且处理继续,因为作业已经运行,没有任何伤害没有犯规。

但偶尔,我会在“作业历史记录”视图中收到一条消息(请记住上面的代码,以检测特定作业是否正在运行,如果没有实际从另一个作业运行则启动它)说该作业失败,因为“SQLAgent拒绝启动这项工作,因为它已有待处理的请求”。

当然,这是TRY CATCH应该处理的确切错误!

当发生这种情况时,正在执行的工作就会消失,但不能立即从我所知道的情况开始,只是非常接近。我把日志记录到了所有地方并且没有一致性。有一次它失败了,它将在a处,a下一次在b处。在某些情况下,地点A和地方B只有

select @var = 'message'
在他们之间。很奇怪。基本上,这项工作似乎是毫不客气地被抛弃的,而且在工作中执行的任何事情都不会被执行。

但是,如果我删除“exec StartJob”(或者只调用一次,当我知道目标作业还不能运行时),一切都运行良好,我在工作中的所有处理都会运行。

所有这一切背后的目的是让一个工作因触发器(以及其他事情)而开始,如果工作已经开始,那么就没有必要“再次启动它”。

任何人都遇到过这样的行为,使用SQL Agent的作业处理?

编辑: 目前的控制流程如下:

  1. 更改为表格(更新或插入)...
  2. 触发调用的触发器......
  3. 存储过程调用...
  4. sp_Start_Job ......
  5. 开始一项特定的工作......
  6. 调用另一个存储过程(称为CheckQueue)......
  7. 执行一些处理......
  8. 检查几个表并根据其内容可能......
  9. 在另一个作业上调用sp_start_job以启动第二个同时作业 处理额外的工作(第二个工作也调用CheckQueue sproc 但是这两个调用对完全独立的数据集进行操作)

3 个答案:

答案 0 :(得分:4)

首先,你有没有机会看服务经纪人?根据您的描述,听起来就像您真正想要的那样。

不同之处在于,不是启动作业,而是将数据放入SB队列,SB将异步调用处理过程并完全解决已经运行的作业等问题。它将自动生成/终止其他线程和需求决定,它照顾秩序等。

这是一个很好的(和模糊的相关)教程。 http://www.sqlteam.com/article/centralized-asynchronous-auditing-with-service-broker

让我们假设您不能出于任何原因使用SB(但严重的是,做!)。

使用作业spid的context_info怎么样?

  1. 你的工作调用一个包装程序proc,它单独执行每一步。
  2. 包装器proc中的第一个语句是

    DECLARE @context_info VARBINARY(30)
    SET @context_info = CAST('MyJob1' AS VARBINARY)
    SET CONTEXT_INFO @context_info
    
  3. 当你的过程结束时(或在你的阻挡区中)

    SET CONTEXT_INFO 0x0
    
  4. 当您正在考虑打电话时,请执行以下操作:

    IF NOT EXISTS (SELECT * FROM master..sysprocesses WITH (NOLOCK) WHERE context_info=CAST('MyJob1' AS VARBINARY))
        EXEC StartJob
    
  5. 当你的包装器proc终止或连接关闭时,你的context_info就会消失。

    您还可以使用全局临时表(即## JobStatus)当引用它的所有spid断开连接或显式删除时,它们将消失。

    只是一些想法。

答案 1 :(得分:2)

我有一个查询,它可以为我提供正在运行的工作,也许它可以帮到你。它一直在为我工作,但如果你发现它有任何错误,请告诉我,我会尽力纠正。欢呼声。

-- get the running jobs
--marcelo miorelli
-- 10-dec-2013


SELECT sj.name
      ,DATEDIFF(SECOND,aj.start_execution_date,GetDate()) AS Seconds
 FROM msdb..sysjobactivity aj
 JOIN msdb..sysjobs sj on sj.job_id = aj.job_id
WHERE aj.stop_execution_date IS NULL -- job hasn't stopped running
 AND aj.start_execution_date IS NOT NULL -- job is currently running
--AND sj.name = 'JobName'
and not exists( -- make sure this is the most recent run
    select 1
    from msdb..sysjobactivity new
    where new.job_id = aj.job_id
      and new.start_execution_date > aj.start_execution_date )

答案 2 :(得分:-3)

处理已经运行的作业: 1.打开任务管理器 2.检查具有ImageName“DTExec.exe”的进程是否正在运行 3.如果进程正在运行且是否有问题,请执行“结束进程”。