如何处理sp_job_start错误?

时间:2018-11-21 18:06:49

标签: sql sql-server error-handling jobs

我有不同的触发因素来启动工作。有时可以设置多个触发器来同时启动该作业,而我的初步检查是看该作业是否运行不正常。

DECLARE @JobCount NUMERIC
SET @JobCount = (SELECT COUNT(*)
                   FROM msdb.dbo.sysjobactivity ja
                   JOIN msdb.dbo.sysjobs j
                        ON ja.job_id = j.job_id
                  WHERE j.name = 'JobName'
                        AND ja.start_execution_date IS NOT NULL
                        AND ja.stop_execution_date IS NULL) 

IF @JobCount = 0
  BEGIN
    EXEC msdb.dbo.sp_start_job 
         'JobName'
  END

这是在触发器的底部,但是如果同时启动触发器,它仍会以Error: Request to run job JobName refused because the job is already running from a request by User错误出现。 BEGIN TRY / CATCH在这里不起作用。我知道在Oracle中别人可能为NULL时可能会有例外-如果发生错误,我可以在这里做任何忽略错误的事情吗?我了解该作业仍在运行,只是不想产生错误。

谢谢

编辑:黑客解决方法是添加WAITFOR DELAY '00:00:01',但也可以接受其他建议

1 个答案:

答案 0 :(得分:0)

由于有多个调用该作业的触发器,因此您引入了竞争条件,因此导致该竞争的相同触发器不太可能解决该问题。您需要一个外部观察员。

您可以尝试...

创建一个新表,例如:

CREATE TABLE JobControl
(
     Id INT IDENTITY(1,1) PRIMARY KEY,
     DateCreated DATETIME DEFAULT CURRENT_TIMESTAMP
)

更改触发器,以便它们在此表中插入一行,而不是调用作业。

创建第二个作业,该作业每 n 秒运行一次(或根据需要不断循环)。该作业将检查JobControl表中的行。如果找到行(通过删除行),它将运行主作业(如果尚未运行)。如果它从该表中删除了行,并且发现该作业已经在运行,它将中止并将其放回下一次。

例如:

SET NOCOUNT ON

DECLARE @MYID UNIQUEIDENTIFIER, @rowsDeleted INT
SELECT @MYID=JOB_ID FROM MSDB.DBO.SYSJOBS WHERE NAME='JobName'

CREATE TABLE #enum_job
(
  Job_ID UNIQUEIDENTIFIER,
  Last_Run_Date INT,
  Last_Run_Time INT,
  Next_Run_Date INT,
  Next_Run_Time INT,
  Next_Run_Schedule_ID INT,
  Requested_To_Run INT,
  Request_Source INT,
  Request_Source_ID VARCHAR(100),
  Running INT,
  Current_Step INT,
  Current_Retry_Attempt INT,
  State INT
)

IF @MYID IS NOT NULL
BEGIN
    BEGIN TRAN
        -- delete all rows in table, capture row count
        DELETE J
        FROM JobControl J
        SET @rowsDeleted=@@ROWCOUNT

        -- check running jobs
        INSERT INTO #enum_job
        EXEC master.dbo.xp_sqlagent_enum_jobs 1, NULL

        -- if the job isn't running, and we had rows to delete, run the job
        IF EXISTS (SELECT 1 FROM #enum_job WHERE Job_ID=@MYID AND Running=0) AND @rowsDeleted>0
        BEGIN
            EXEC msdb.dbo.sp_start_job 'JobName'
        END

        -- if the job is already running, and we had rows to delete, roll back
        IF EXISTS (SELECT 1 FROM #enum_job WHERE Job_ID=@MYID AND Running=1) AND @rowsDeleted>0
        BEGIN
            ROLLBACK TRAN
        END
    -- if the transaction is still open, commit it
    IF @@TRANCOUNT>0 COMMIT TRAN
END