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

Sql server 如何准确地检测SQL Server作业是否正在运行并处理已在运行的作业?,sql-server,tsql,sql-server-agent,sql-agent-job,Sql Server,Tsql,Sql Server Agent,Sql Agent Job,我目前正在使用这样的代码来检测SQL server作业是否正在运行。(这是SQL Server 2005,所有SP) 没有问题,一般来说,它工作得很好 但是。。。。(总是一个但是) 有时,我会调用它,得到一个“job is not running”结果,在这一点上,我会尝试通过 exec msdb.dbo.sp_start_job @JobName SQL将返回“SQLAgent拒绝启动作业,因为它已经有一个挂起的请求” 嗯。也不是问题。可以想象,在这段代码可以启动目标作业之前,但在检查它是否

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

没有问题,一般来说,它工作得很好

但是。。。。(总是一个但是)

有时,我会调用它,得到一个“job is not running”结果,在这一点上,我会尝试通过

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代理将引发错误,它被捕获,处理将继续进行,因为作业已在运行,没有伤害也没有犯规

但偶尔,我会在Job History视图中看到一条消息(请记住上面的代码,以检测特定作业是否正在运行,如果不是从另一个作业实际运行,则启动该作业),该消息说该作业失败,因为“SQLAgent已拒绝启动该作业,因为它已经有一个挂起的请求”

当然,这正是TRY-CATCH应该处理的错误

当这种情况发生时,正在执行的作业就消失了,但据我所知,并不是立即消失,只是非常接近。我把日志放得到处都是,没有一致性。一次失败,它将在位置a,下一次在位置b。在某些情况下,地点A和地点B只有A

select @var = 'message'
在他们之间。很奇怪。基本上,作业似乎被随意转储,作业中剩下的任何要执行的内容都是+不+执行的

但是,如果我删除了“exec StartJob”(或者在我知道目标作业不能运行的情况下,只调用了一次),那么一切都会正常工作,作业中的所有处理都会完成

这一切背后的目的是让作业作为触发器启动(除其他外),并且,如果作业已经启动,实际上没有必要“重新启动”

有人在SQL代理的作业处理中遇到过这样的行为吗

编辑: 当前的控制流程如下所示:

  • 更改为表(更新或插入)
  • 触发调用
  • 调用
  • sp_启动_作业,其中
  • 启动一个特定的作业,该作业
  • 调用另一个存储的进程(称为CheckQueue),该进程
  • 执行一些处理和
  • 检查多个表,根据其内容可能
  • 在另一个作业上调用sp_start_job以启动第二个同步作业 要处理附加工作(第二个作业也会调用CheckQueue存储过程) 但这两个调用操作的是完全不同的数据集)

  • 首先,您是否有机会了解ServiceBroker?根据你的描述,听起来这就是你真正想要的

    不同之处在于,您没有启动作业,而是将数据放入SB队列,SB将异步调用您的处理过程,并完全解决已运行作业的问题等。它将自动生成/终止其他线程和请求指示,它将处理订单等

    这里有一个很好的(和模糊相关的)教程

    让我们假设你不能出于任何原因使用某人(但说真的,一定要使用!)

    使用作业spid的上下文信息怎么样

  • 作业调用单独执行每个步骤的包装程序
  • 包装程序中的第一条语句是

    DECLARE @context_info VARBINARY(30)
    SET @context_info = CAST('MyJob1' AS VARBINARY)
    SET CONTEXT_INFO @context_info
    
  • 当你的进程结束时(或在你的捕获块中)

  • 当你考虑给你的工作打电话时,请这样做:

    IF NOT EXISTS (SELECT * FROM master..sysprocesses WITH (NOLOCK) WHERE context_info=CAST('MyJob1' AS VARBINARY))
        EXEC StartJob
    
  • 当包装程序终止或连接关闭时,您的上下文信息就会消失

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


    请考虑一下。

    要处理已在运行的作业,请执行以下操作: 1.开放式任务管理器 2.检查ImageName为“DTExec.exe”的进程是否正在运行
    3.如果进程正在运行,并且是有问题的作业,请执行“结束进程”。

    我有一个查询,提供了正在运行的作业,也许它可以帮助您。它一直在为我工作,但如果你发现它的任何缺点,让我知道,我会尝试纠正。干杯

    -- 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 )
    

    这不是我真正想要的答案,但作为一种解决方法,我创建了一个“monitor”表,其中包含一个标志,指示每个特定作业是否“真正”运行,以及防止失败的过期时间。因此,如果此标志指示作业未运行,则它无法运行,因此启动它是安全的。如果它指示它正在运行,我将使用sp_help_job方法检查作业是否正在运行。如果返回的结果是它没有运行。我撞上一个计数器并继续。如果计数器连续撞x次,间隔一定的时间,那么我可以合理地确定作业实际上没有运行,清除其状态并使其可以再次运行。虽然我不知道上下文信息功能,但仍然希望有一个不太迂回的解决方案。有趣的是,在一天结束时,这种方法基本上与使用表相同,行中包含作业的spid和一些跟踪信息。不过可能要简单一点(因为工作完成后,上下文信息会自动消失。我最初查看了ServiceBroker,但客户拒绝了,因为他们的员工中没有人知道任何有关它的信息。不过,对于类似的未来项目,ServiceBroker的内容肯定在我的脑海中。谢谢!我对此表示赞同,主要是因为1)它
    IF NOT EXISTS (SELECT * FROM master..sysprocesses WITH (NOLOCK) WHERE context_info=CAST('MyJob1' AS VARBINARY))
        EXEC StartJob
    
    -- 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 )