我一直在努力复制AutoSys的Box功能。我遇到了一个此处显示的解决方案(https://dba.stackexchange.com/a/161658),该解决方案非常非常好。我开始添加它,检查结果,并添加了对我们使用的另一个ETL解决方案的处理。
我遇到麻烦的地方是,我没有意识到没有检查工作是否有效的情况。如果工作名称拼写错误,或者有人删除工作,我想检查一下。我不想假设某项工作没有执行。我添加了对有效SQL Agent作业名称的检查。如果作业名称有效,则此方法有效。但是,如果作业名称无效,该过程将陷入显示错误消息“ NO JOB”的循环中,直到我停止该过程为止。
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[usp_start_job_sequence8]
(
@JobList JobSequenceTable READONLY
,@PrntJob VARCHAR(100) = 'Unknown_Job'
)
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
SET QUOTED_IDENTIFIER ON;
SET ANSI_NULLS ON;
SET ANSI_PADDING ON;
SET ARITHABORT ON;
SET CONCAT_NULL_YIELDS_NULL ON;
SET NUMERIC_ROUNDABORT OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET ANSI_WARNINGS OFF;
---------------------************TRY BLOCK************---------------------
BEGIN TRY
BEGIN
DECLARE
@JobNumber TINYINT = 1
,@JobName VARCHAR(100)
,@IsRunning BIT
,@IsEnabled BIT
,@JOB_ID VARCHAR(60) = NULL
,@JOB_HIST_ID INT
,@JOB_STATUS VARCHAR(30)
,@JOB_STATUS_ID INT
,@esub VARCHAR(100)
,@ebdy VARCHAR(500)
,@Envt VARCHAR(4)
,@OVJOB_ID VARCHAR(60)
,@OVJOB_NAME VARCHAR(120)
,@JOB_TYPE CHAR(3)
,@epri VARCHAR(6);
--- Set server environment for emails
SELECT
@Envt = CASE WHEN @@SERVERNAME LIKE '%D%' THEN 'Dev'
WHEN @@SERVERNAME LIKE '%U%' THEN 'UAT'
WHEN @@SERVERNAME LIKE '%P%' THEN 'Prod'
WHEN @@SERVERNAME LIKE '%R%' THEN 'BCP'
ELSE ''
END
--- Set server environment for email priority
,@epri = CASE WHEN @@SERVERNAME LIKE '%D%' THEN 'Low'
WHEN @@SERVERNAME LIKE '%U%' THEN 'Normal'
WHEN @@SERVERNAME LIKE '%P%' THEN 'High'
WHEN @@SERVERNAME LIKE '%R%' THEN 'High'
ELSE ''
END;
BEGIN
WHILE (@JobNumber <= (SELECT
MAX(JobNumber)
FROM
@JobList
))
BEGIN
SELECT
@JobName = JobName
FROM
@JobList
WHERE
JobNumber = @JobNumber;
--VALID JOB?
IF NOT EXISTS(SELECT j.name FROM msdb.dbo.sysjobs_view J WITH(NOLOCK)
WHERE j.Name = @JobName)
BEGIN
PRINT 'NO JOB'
END;
ELSE
BEGIN
PRINT 'YES WE FOUND THE JOB';
--END
SELECT
@JOB_ID = job_id
FROM
msdb.dbo.sysjobs_view
WHERE
name = @JobName;
SELECT
@IsEnabled = enabled
FROM
msdb.dbo.sysjobs_view
WHERE
name = @JobName;
--- Very important step here. Ouvvi job names must start with Ouvvi
SELECT
@JOB_TYPE = CASE WHEN @JobName LIKE 'Ouvvi%'
THEN 'OVI'
ELSE 'SQL'
END;
--- Check if the job already running
SELECT
@IsRunning = dbo.fnJobStatusCheck(@JobName);
IF @IsRunning = 0
BEGIN
IF @IsEnabled = 0 --- Job is disabled error and send email
BEGIN
PRINT 'Job ' + @JobName
+ ' is disabled and cannot be started';
SET @esub = 'SQL Agent job '
+ @JobName + ' in ' + @Envt
+ ' is disabled and cannot be started';
SET @ebdy = 'SQL Agent job '
+ @JobName
+ ' was scheduled to run in box job '
+ @PrntJob + ' on server '
+ @@SERVERNAME + '. '
+ @JobName
+ ' could not start as it is disabled.'
+ CHAR(10) + CHAR(13)
+ +'The job ' + @JobName
+ ' should either be enabled, or removed from box job '
+ @PrntJob + '.';
EXEC msdb.dbo.sp_send_dbmail
--@profile_name = '',
-- @recipients = 'group@mail.com'
@recipients = 'person@mail.com',
@importance = @epri,
@subject = @esub,@body = @ebdy;
END;
ELSE ---- @IsEnabled = 1
----- Job is not running nor disabled. Split for different types
---OUVVI
BEGIN
IF @JOB_TYPE = 'OVI'
BEGIN
--PRINT 'OUVVI JOB'; --- TESTING
--- Parse Ouvvi Project ID - Used for success-failure
SET @OVJOB_ID = (SELECT
RTRIM(SUBSTRING(command,
CHARINDEX('/start/',
command) + 7,3))
FROM
msdb.dbo.sysjobsteps
WHERE
job_id = @JOB_ID
AND step_id = 1
);
--- START Ouvvi Job
EXEC msdb.dbo.sp_start_job @job_name = @JobName;
--PRINT @OVJOB_ID; --- TESTING
-- Waiting for the job to finish - Ouvvi jobs don't start immediately
WAITFOR DELAY '00:00:01';
WHILE (SELECT
1
FROM
Ouvvi.dbo.Queue
WHERE
ProjectID = @OVJOB_ID
) IS NOT NULL
BEGIN
WAITFOR DELAY '00:00:15';
IF (SELECT
1
FROM
Ouvvi.dbo.Queue
WHERE
ProjectID = @OVJOB_ID
) IS NULL
BREAK;
END;
--- Get Ouvvi Job Hist ID
SET @JOB_HIST_ID = (SELECT
Instance.ID
FROM
Ouvvi.dbo.Instance
WHERE
Instance.ProjectID = @OVJOB_ID
AND Instance.EndTime = (SELECT
MAX(EndTime)
FROM
Ouvvi.dbo.Instance
WHERE
Instance.ProjectID = @OVJOB_ID
)
);
--- Get Ouvvi Result
SET @JOB_STATUS_ID = (SELECT
ISNULL(I.Result,
9)
FROM
Ouvvi.dbo.Instance I
WHERE
I.ID = @JOB_HIST_ID
);
SET @JOB_STATUS = (SELECT
CASE
WHEN I.Result = 1
THEN 'Succeeded'
WHEN I.Result = 2
THEN 'Failed'
WHEN I.Result = 3
THEN 'Cancelled'
ELSE 'Unknown'
END
FROM
Ouvvi.dbo.Instance I
WHERE
I.ID = @JOB_HIST_ID
);
IF @JOB_STATUS_ID <> 1
BEGIN
PRINT @JobName
+ ' erred with the following status: '
+ @JOB_STATUS;
SET @esub = 'Ouvvi SQL Agent job '
+ @JobName
+ ' in ' + @Envt
+ ' erred with the following status: '
+ @JOB_STATUS;
SET @ebdy = 'An Ouvvi job, scheduled in SQL Agent '
+ @JobName
+ ' has erred with the following status: '
+ @JOB_STATUS
+ ' on server '
+ @@SERVERNAME
+ '.';
EXEC msdb.dbo.sp_send_dbmail
--@profile_name = '',
-- @recipients = 'group@mail.com'
@recipients = 'person@mail.com',
@importance = @epri,
@subject = @esub,
@body = @ebdy;
END;
END;
----Its a SQL Server Job
ELSE
BEGIN
EXEC msdb.dbo.sp_start_job @job_name = @JobName;
END;
WAITFOR DELAY '00:00:15.000';
SELECT
@IsRunning = dbo.fnJobStatusCheck(@JobName);
WHILE @IsRunning = 1
BEGIN
WAITFOR DELAY '00:00:15.000';
SELECT
@IsRunning = dbo.fnJobStatusCheck(@JobName);
END;
BEGIN
SET @JOB_HIST_ID = (SELECT
job_history_id
FROM
msdb.dbo.sysjobactivity
WHERE
job_id = @JOB_ID
AND run_requested_date = (SELECT
MAX(run_requested_date)
FROM
msdb.dbo.sysjobactivity
WHERE
job_id = @JOB_ID
)
);
SET @JOB_STATUS_ID = (SELECT
ISNULL(run_status,
9)
FROM
msdb.dbo.sysjobhistory
WHERE
instance_id = @JOB_HIST_ID
);
SET @JOB_STATUS = (SELECT
CASE
WHEN @JOB_STATUS_ID = 0
THEN 'Failed'
WHEN @JOB_STATUS_ID = 1
THEN 'Succeeded'
WHEN @JOB_STATUS_ID = 2
THEN 'Retry'
WHEN @JOB_STATUS_ID = 3
THEN 'Cancelled'
ELSE 'Unknown'
END
);
BEGIN
IF @JOB_STATUS_ID <> 1
BEGIN
PRINT @JobName
+ ' erred with the following status: '
+ @JOB_STATUS;
SET @esub = 'SQL Agent job '
+ @JobName
+ ' in ' + @Envt
+ ' erred with the following status: '
+ @JOB_STATUS;
SET @ebdy = 'SQL Agent job '
+ @JobName
+ ' erred with the following status: '
+ @JOB_STATUS
+ ' on server '
+ @@SERVERNAME
+ '.';
EXEC msdb.dbo.sp_send_dbmail
--@profile_name = '',
-- @recipients = 'group@mail.com'
@recipients = 'person@mail.com',
@importance = @epri,
@subject = @esub,
@body = @ebdy;
END;
END;
END;
END;
SET @JOB_ID = NULL;
SET @JobNumber = @JobNumber + 1;
END;
END;
END;
END;
END;
END TRY
---------------------*********************************--------------------
---------------------************CATCH BLOCK**********-------------------
BEGIN CATCH
-- Print Error Information
DECLARE @ERRORMESSAGE NVARCHAR(4000);
DECLARE @ERRORSEVERITY INT;
DECLARE @ERRORSTATE INT;
SELECT
@ERRORMESSAGE = ERROR_MESSAGE()
,@ERRORSEVERITY = ERROR_SEVERITY()
,@ERRORSTATE = ERROR_STATE();
RAISERROR (@ERRORMESSAGE, @ERRORSEVERITY, @ERRORSTATE);
-- Rollback uncommittable transactions
IF (XACT_STATE()) = -1
BEGIN
PRINT 'The transaction is in an uncommittable state.'
+ ' Rolling back transaction.';
ROLLBACK TRANSACTION;
END;
-- Inserting error related information into the Error Log table
INSERT INTO dbo.tbl_Object_ErrorLog
(ObjectName
,ErrorNumber
,ErrorMessage
,ErrorSeverity
,ErrorState
,ErrorlINE
,SystemUser
,LogDate
)
SELECT
ERROR_PROCEDURE()
,ERROR_NUMBER()
,ERROR_MESSAGE()
,ERROR_SEVERITY()
,ERROR_STATE()
,ERROR_LINE()
,SYSTEM_USER
,GETDATE();
END CATCH;
---------------------********************************----------------------
END;
GO
启动该过程的代码:
SET ANSI_WARNINGS OFF
GO
DECLARE @JobList AS JobSequenceTable
INSERT INTO @JobList
VALUES
('x_test3')
,('NoJobHere')
,('x_test1')
EXEC dba.dbo.usp_start_job_sequence8 @JobList, 'TESTING'
我想发生的是:当它检查有效的作业名称时,不打印任何作业并结束,它应该转到行378,将1添加到@JobNumber,结束该回合,转到下一个作业。
我不知道为什么它会陷入循环。 感谢您的帮助。
答案 0 :(得分:1)
由于您的循环非常长,且带有嵌套块且难以调试,因此我将执行以下操作:
-在跳入循环之前,请确认缺少哪些作业
-创建一个表,其中包含丢失的作业,例如@MissingJobs,然后在处理现有工作之前先与他们做事
-基于@MissingJobs,从@JobList表中删除丢失的作业,然后循环遍历,因此在这种情况下,无需调试长循环块。或者,如果需要原始表并在循环中使用它,则可以创建一个新表-但在这种情况下,需要进行更多工作以从@JobList更改为新表。如果您将所有缩减的@JobList与@MissingJobs结合在一起,则可以返回原始列表。无论如何,您需要在--VALID JOB之后删除该块吗? (直到PRINT'YES WE FOUND JOB';为止),因为您可以根据此逻辑将其打印出来-在这种情况下,还必须在SET @JobNumber = @JobNumber + 1之后删除END;因为您删除了未关闭的ELSE BEGIN。