我目前正在使用这样的代码来检测 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 代理的作业处理中遇到过这样的行为吗?
编辑:当前的控制流程是这样的:
- 更改为表(更新或插入)...
- 触发触发调用...
- 一个存储过程,它调用...
- sp_Start_Job 其中...
- 开始一项特定的工作...
- 调用另一个存储过程(称为 CheckQueue)...
- 执行一些处理并...
- 检查几个表,根据它们的内容可能...
- 在另一个作业上调用 sp_start_job 以启动第二个同时作业来处理额外的工作(第二个作业也调用 CheckQueue 存储过程,但两个调用对完全独立的数据集进行操作)