5

sp_start_job用来开始工作。

作业 ( test2) 只有一步:

select getdate()
waitfor delay '00:00:10'

TRY/CATCH代码:

begin try
    EXEC msdb.dbo.sp_start_job @job_name = 'test2'
end try
begin catch
    print 'error'
end catch

第一次运行代码:

作业“test2”成功启动。

代码的第二次运行(10 秒内):

消息 22022,级别 16,状态 1,第 0 行
SQLServerAgent 错误:运行作业 test2 的请求(来自用户 sa)被拒绝,因为作业已经从用户 sa 的请求中运行。

为什么TRY/CATCH在这种情况下不起作用?

更新:我首先应该补充一点,我正在使用具有链接服务器(sql server 2000)的 sql server 2005。我试图在 sql server 2005 服务器上编写一个 proc,以查看所有链接服务器上的作业。如果作业未运行,请运行它。最初,我使用 try - catch 并希望在运行已经运行的作业但失败(此线程)时捕获任何错误。

我终于使用了以下代码:(它不会编译,你需要替换一些变量,只是给出一个想法)

    CREATE TABLE [dbo].[#jobInfo](
        [job_id] [uniqueidentifier] NULL,
        [originating_server] [nvarchar](30) ,
        [name] [nvarchar](128) ,
        [enabled] [tinyint] NULL,
        [description] [nvarchar](512) ,
        [start_step_id] [int] NULL,
        [category] [nvarchar](128) ,
        [owner] [nvarchar](128) ,
        [notify_level_eventlog] [int] NULL,
        [notify_level_email] [int] NULL,
        [notify_level_netsend] [int] NULL,
        [notify_level_page] [int] NULL,
        [notify_email_operator] [nvarchar](128) ,
        [notify_netsend_operator] [nvarchar](128) ,
        [notify_page_operator] [nvarchar](128) ,
        [delete_level] [int] NULL,
        [date_created] [datetime] NULL,
        [date_modified] [datetime] NULL,
        [version_number] [int] NULL,
        [last_run_date] [int] NOT NULL,
        [last_run_time] [int] NOT NULL,
        [last_run_outcome] [int] NOT NULL,
        [next_run_date] [int] NOT NULL,
        [next_run_time] [int] NOT NULL,
        [next_run_schedule_id] [int] NOT NULL,
        [current_execution_status] [int] NOT NULL,
        [current_execution_step] [nvarchar](128) ,
        [current_retry_attempt] [int] NOT NULL,
        [has_step] [int] NULL,
        [has_schedule] [int] NULL,
        [has_target] [int] NULL,
        [type] [int] NOT NULL
    )


    SET @sql = 
    'INSERT INTO #jobInfo
    SELECT * FROM OPENQUERY( [' + @srvName + '],''set fmtonly off exec msdb.dbo.sp_help_job'')'

    EXEC(@sql)

    IF EXISTS (select * from #jobInfo WHERE [name] = @jobName AND current_execution_status IN (4,5)) -- 4: idle, 5: suspended 
    BEGIN
        SET @sql = 'EXEC [' + @srvName + '].msdb.dbo.sp_start_job @job_name = ''' + @jobName + ''''
        --print @sql    
        EXEC (@sql) 
        INSERT INTO #result (srvName ,status ) VALUES (@srvName, 'Job started.')
    END ELSE BEGIN
        INSERT INTO #result (srvName ,status ) VALUES (@srvName, 'Job is running already. No action taken.')
    END
4

4 回答 4

8

并非所有错误都能被TRY/CATCH. 在这种情况下,sp_start_job实际上调用了外部过程,而这些超出了 SQL Server 错误处理的范围。或者至少这是他们坚持的故事:

http://connect.microsoft.com/SQLServer/feedback/details/362112/sp-start-job-error-handling

另请注意,这在 SQL Server 2012 SP1 CU3 中仍然是一个问题。如果您想修复此错误,请投票和评论。

一个乏味但可行的解决方法,需要一定的权限,在这种情况下假设工作​​所有者是sa

DECLARE @x TABLE
(
  a VARBINARY(32),b INT,c INT,d INT,e INT,f INT,g INT,h INT,i NVARCHAR(64),
  Running BIT, -- the only important column
  k INT,l INT,m INT
);

DECLARE @job_id UNIQUEIDENTIFIER;

SELECT @job_id = job_id FROM msdb.dbo.sysjobs WHERE name = N'test2';

INSERT @x EXEC master.dbo.xp_sqlagent_enum_jobs 1, N'sa', @job_id;

IF EXISTS (SELECT 1 FROM @x WHERE Running = 0)
BEGIN
     EXEC msdb.dbo.sp_start_job @job_name = N'test2';
END
ELSE
BEGIN
     PRINT 'error';
END

更好的可能是:

DECLARE @job_id UNIQUEIDENTIFIER, @d DATETIME;

SELECT @job_id = job_id FROM msdb.dbo.sysjobs WHERE name = N'test2';

SELECT @d = stop_execution_date 
  FROM msdb.dbo.sysjobactivity WHERE job_id = @job_id;

IF @d IS NOT NULL
BEGIN
     EXEC msdb.dbo.sp_start_job @job_name = N'test2';
END
ELSE
BEGIN
     PRINT 'error';
END

在任何一种情况下,作业仍有可能在检查其状态和调用启动它之间开始,因此这并不能sp_start_job完全消除错误,但它使它们发生的可能性大大降低。

于 2013-03-27T12:48:02.013 回答
1

You can use alerts to execute SQL Agent jobs. And you can use alerts' options to configure required response. (this will help you to totally avoid error 22022 but you will have additional records in the errorlog)

于 2018-08-08T10:56:40.977 回答
0

为了制定一个常青的解决方案,我们还应该考虑一个以前从未运行过的工作。这在重建 SQL 服务器和重新创建作业的情况下很有用。要捕获该场景,请查看上次运行请求的日期:

DECLARE @jobEnd DATETIME, @jobRun DATETIME
SELECT @jobEnd = sja.stop_execution_date , @jobRun = sja.run_requested_date
FROM msdb.dbo.sysjobactivity AS sja
INNER JOIN msdb.dbo.sysjobs AS sj
ON sja.job_id = sj.job_id
WHERE sj.name = 'PhoneListSyncMember'

IF (@jobEnd IS NOT NULL AND @jobRun IS NOT NULL)
  OR (@jobEnd IS NULL AND @jobRun IS NULL)  -- job is New and never run before
    EXEC @iRet =msdb.dbo.sp_start_job @job_name='PhoneListSyncMember'
于 2021-05-20T00:14:20.857 回答
0

这是捕获作业触发器失败的方法。

声明@returnstatus int

执行@returnstatus msdb.dbo.sp_start_job '作业名'

if(@returnstaus = 1) 打印“成功”,否则打印“失败”

于 2020-11-04T08:33:26.523 回答