10

我目前正在使用这样的代码来检测 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 代理将引发错误,它被捕获,然后继续处理,因为作业已经在运行,没有伤害没有犯规。

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

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

发生这种情况时,正在执行的工作就会死掉,但据我所知,不会立即死掉,只是非常接近。我已经把日志记录在所有地方,并且没有一致性。一次失败,它会在a地,下一次在b地。在某些情况下,地点 A 和地点 B 只有一个

select @var = 'message'

在他们之间。很奇怪。基本上,该作业似乎被毫不客气地转储了,并且该作业中剩下要执行的任何内容都不会+执行。

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

这一切背后的目的是让一个工作作为触发器的结果开始(除其他外),如果工作已经开始,真的没有必要“重新开始”。

任何人都曾在 SQL 代理的作业处理中遇到过这样的行为吗?

编辑:当前的控制流程是这样的:

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

3 回答 3

4

首先,您有机会了解服务代理吗?根据您的描述,这听起来像是您真正想要的。

不同之处在于您将数据放入 SB 队列而不是开始作业,SB 将异步调用您的处理过程,并完全避开已经运行的作业等问题。它将自动产生/终止额外的线程和需求指示,它负责订单等。

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

让我们假设您不能出于任何原因使用 SB(但说真的,这样做!)。

如何使用作业 spid 的 context_info。

  1. 您的工作调用了一个单独执行每个步骤的包装程序。
  2. 包装过程中的第一条语句是

    DECLARE @context_info VARBINARY(30)
    SET @context_info = CAST('MyJob1' AS VARBINARY)
    SET CONTEXT_INFO @context_info
    
  3. 当您的 proc 完成时(或在您的 catch 块中)

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

    IF NOT EXISTS (SELECT * FROM master..sysprocesses WITH (NOLOCK) WHERE context_info=CAST('MyJob1' AS VARBINARY))
        EXEC StartJob
    

当您的包装程序终止或连接关闭时,您的 context_info 就会消失。

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

只是一些想法。

于 2011-08-03T17:35:25.453 回答
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 )
于 2014-09-27T14:52:31.437 回答
-3

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

于 2013-07-10T11:16:17.610 回答