Since I seem to run across lots of questions about how to make sure that no jobs get in the way of ETL or other stressful data loads, I thought that I should post some ways you can stop jobs.
I have always done this by having a monitoring job that executes on a schedule that runs at a time when you need other jobs to stop. Of course, you need to be aware that stopping jobs can come with unwanted side effects of some data change that may be unfinished (there may be a rollback) and the stopped job will have to gracefully be re-run at another time. You will also see the stopped job as cancelled in the job activity monitor. And, hopefully you are aware that you can tell a job to stop but if it is doing work using a linked server, it may not stop as expected or it can take a while if it is rolling back a transaction.
But let’s get down to business….Here’s the straightforward and simple way:
EXEC msdb.dbo.sp_stop_job @job_name = ‘DBMaint.UpdateStatistics’
But…..if you have to get creative and get a list of all jobs that are running and stop them it gets a bit more complicated. Maybe you can’t have anything running after 3am because you have a nightly ETL process that starts then. Simply run this code in your “Stop at 2:55AM” job and you are ready for the ETL to start.
DECLARE @MaxRunMin INT DECLARE @JobName VARCHAR(250) SET @MaxRunMin = 120 -- 2 hours -- create temp table in case more than one job is found IF (SELECT OBJECT_ID('tempdb..#JobsToStop')) IS NOT NULL DROP TABLE #JobsToStop CREATE TABLE #JobsToStop (JobName VARCHAR(250)); INSERT INTO #JobsToStop SELECT sj.name FROM msdb.dbo.sysjobactivity ja JOIN msdb.dbo.sysjobs sj ON sj.job_id = ja.job_id WHERE ja.stop_execution_date IS NULL -- job hasn't stopped running AND ja.start_execution_date IS NOT NULL -- job is currently running AND DATEDIFF(MINUTE,ja.start_execution_date,GETDATE()) > @MaxRunMin -- job has been running longer than max mins ORDER BY ja.start_execution_date DECLARE joblist CURSOR FOR SELECT JobName FROM #JobsToStop OPEN joblist FETCH NEXT FROM joblist INTO @JobName WHILE @@FETCH_STATUS=0 BEGIN EXEC msdb.dbo.sp_stop_job @job_name = @JobName PRINT 'Stopped ' + @JobName FETCH NEXT FROM joblist INTO @JobName END CLOSE joblist DEALLOCATE joblist
I can take the above code and by adding some things (like category) I can get more specific on what jobs we stop. Job categories are located in msdb.
select * from msdb.dbo.syscategories
There is a category for Database Maintenance and, as you can see, you can create your own custom categories if it makes job management easier.
EXEC msdb.dbo.sp_add_category @class=N’JOB’, @type=N’LOCAL’, @name=N’SQLRX’
And now we can stop any Database Maintenance jobs that are currently running longer than 2 hours.
-- Check to see if Maintenance jobs are running too long and stop them DECLARE @MaxRunMin INT DECLARE @JobName VARCHAR(250) SET @MaxRunMin = 120 -- 2 hours -- create temp table in case more than one job is found IF (SELECT OBJECT_ID('tempdb..#JobsToStop')) IS NOT NULL DROP TABLE #JobsToStop CREATE TABLE #JobsToStop (JobName VARCHAR(250)); INSERT INTO #JobsToStop SELECT sj.name FROM msdb.dbo.sysjobactivity ja JOIN msdb.dbo.sysjobs sj ON sj.job_id = ja.job_id JOIN msdb.dbo.syscategories sc ON sj.category_id = sc.category_id WHERE ja.stop_execution_date IS NULL -- job hasn't stopped running AND ja.start_execution_date IS NOT NULL -- job is currently running AND DATEDIFF(MINUTE,ja.start_execution_date,GETDATE()) > @MaxRunMin -- job has been running longer than max mins AND sc.name = 'Database Maintenance' -- maintenance category ORDER BY ja.start_execution_date DECLARE joblist CURSOR FOR SELECT JobName FROM #JobsToStop OPEN joblist FETCH NEXT FROM joblist INTO @JobName WHILE @@FETCH_STATUS=0 BEGIN EXEC msdb.dbo.sp_stop_job @job_name = @JobName PRINT 'Stopped ' + @JobName FETCH NEXT FROM joblist INTO @JobName END CLOSE joblist DEALLOCATE joblist
To stop specific jobs from running after a specific time, I simply added a problem jobs variable that can be populated with a comma delimited list of jobs you already know don’t need to be running.
DECLARE @MaxRunMin INT DECLARE @JobName VARCHAR(250) DECLARE @ProblemJobs VARCHAR(MAX) SET @MaxRunMin = 120 -- 2 hours SET @ProblemJobs = 'DBMaint.UpdateStatistics,SQLRX - Defrag' -- comma delimited -- create temp table in case more than one job is found IF (SELECT OBJECT_ID('tempdb..#JobsToStop')) IS NOT NULL DROP TABLE #JobsToStop CREATE TABLE #JobsToStop (JobName VARCHAR(250)); INSERT INTO #JobsToStop SELECT sj.name FROM msdb.dbo.sysjobactivity ja JOIN msdb.dbo.sysjobs sj ON sj.job_id = ja.job_id JOIN msdb.dbo.syscategories sc ON sj.category_id = sc.category_id WHERE ja.stop_execution_date IS NULL -- job hasn't stopped running AND ja.start_execution_date IS NOT NULL -- job is currently running AND DATEDIFF(MINUTE,ja.start_execution_date,GETDATE()) > @MaxRunMin -- job has been running longer than max mins --AND sc.name = 'Database Maintenance' -- maintenance category AND sj.name IN (SELECT * FROM STRING_SPLIT(@ProblemJobs,',')) --List of specific jobs to stop ORDER BY ja.start_execution_date DECLARE joblist CURSOR FOR SELECT JobName FROM #JobsToStop OPEN joblist FETCH NEXT FROM joblist INTO @JobName WHILE @@FETCH_STATUS=0 BEGIN EXEC msdb.dbo.sp_stop_job @job_name = @JobName PRINT 'Stopped ' + @JobName FETCH NEXT FROM joblist INTO @JobName END CLOSE joblist DEALLOCATE joblist
Again, you put the code in a job that runs at whatever time you want these specific jobs to stop.
As you can see, there are many ways to customize this code to do what you want. Hope this is helpful to someone!
For more information about blog posts, concepts and definitions, further explanations, or questions you may have…please contact us at SQLRx@sqlrx.com. We will be happy to help! Leave a comment and feel free to track back to us. Visit us at www.sqlrx.com!
Session expired
Please log in again. The login page will open in a new tab. After logging in you can close it and return to this page.
[…] Lori Brown puts a halt to things: […]