首页 > 解决方案 > 如何处理 sp_job_start 的错误?

问题描述

我有不同的触发器来启动工作。有时可以触发多个触发器同时启动这项工作,并且我最初检查该工作是否运行不正常。

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 中,当 OTHERS 为 NULL 时您可能会遇到异常 -如果发生错误,我可以在这里做些什么来忽略错误?我知道这项工作仍在运行,我只是不想产生错误。

谢谢

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

标签: sqlsql-servererror-handlingjobs

解决方案


通过让多个触发器调用作业,您已经引入了竞争条件,因此导致竞争的相同触发器不太可能解决它。你需要一个外部观察者。

你可以试试...

创建一个新表,例如:

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

推荐阅读