SQL Server Agent Job waiting for a worker thread

Header - SQL Server Agent Job waiting for a worker thread

Recently one of my teammates experienced a quite interesting issue. He was deploying new PowerShell maintenance SQL Server Agent Jobs on a new SQL Server instance. During the final test run, he noticed that some of the jobs were executing fine and one of them was waiting for a worker thread. In this blog post, I will describe what do to if you encounter a similar issue.

PowerShell Job steps

Due to the various circumstances, we had to rewrite some of our maintenance jobs from T-SQL to PowerShell. Created scripts are now executed by Agent Jobs with PowerShell steps. Every job tested separately works fine without any issues. However, when jobs are started simultaneously, only two of them are running, the rest is waiting for worker threads. Usually, you don’t see such things with other job step’s types.

Steps to reproduce

If your SQL Server Agent runs with default configuration values you should be able to easily reproduce this issue.

First of all, you need to create at least 3 SQL Server Agent jobs with PowerShell steps. These steps cannot be the quick ones because you won’t notice this problematic behavior. For testing purpose, we will use the PowerShell Start-Sleep command that waits for a given time. In our case, 60 seconds should be enough.

We will use a temporary stored procedure to make jobs creation easier  (and to make sure we won’t leave any unnecessary objects after we finish our exercise). If you’re not familiar with temporary stored procedures I invite you to read this post: Temporary Stored Procedures – good, old and little-known feature.

USE [msdb]
GO

CREATE PROCEDURE #temp_CreateJob @jobName sysname
AS

    DECLARE @jobId BINARY(16)
    EXEC  msdb.dbo.sp_add_job @job_name=@jobName, 
        @enabled=1, 
        @notify_level_eventlog=0, 
        @notify_level_email=2, 
        @notify_level_page=2, 
        @delete_level=0, 
        @category_name=N'[Uncategorized (Local)]', 
        @owner_login_name=N'sa', @job_id = @jobId OUTPUT;

    EXEC msdb.dbo.sp_add_jobserver @job_name=@jobName, @server_name = @@SERVERNAME;


    EXEC msdb.dbo.sp_add_jobstep @job_name=@jobName, @step_name=N'example', 
        @step_id=1, 
        @cmdexec_success_code=0, 
        @on_success_action=1, 
        @on_fail_action=2, 
        @retry_attempts=0, 
        @retry_interval=0, 
        @os_run_priority=0, @subsystem=N'PowerShell', 
        @command=N'Start-Sleep -Seconds 60', 
        @database_name=N'master', 
        @flags=0;

    EXEC msdb.dbo.sp_update_job @job_name=@jobName, 
        @enabled=1, 
        @start_step_id=1, 
        @notify_level_eventlog=0, 
        @notify_level_email=2, 
        @notify_level_page=2, 
        @delete_level=0, 
        @description=N'',  
        @notify_email_operator_name=N'', 
        @notify_page_operator_name=N'';
GO

To create three new jobs run below query.

EXEC #temp_CreateJob @jobName = N'test1'
EXEC #temp_CreateJob @jobName = N'test2'
EXEC #temp_CreateJob @jobName = N'test3'
GO

SELECT * FROM msdb.dbo.sysjobs WHERE [name] LIKE 'test_'
GO

Three new SQL Server jobs should now appear in SSMS Object Explorer.

Jobs

Let’s run all at once now.

EXEC msdb.dbo.sp_start_job @job_name=N'test1';
EXEC msdb.dbo.sp_start_job @job_name=N'test2';
EXEC msdb.dbo.sp_start_job @job_name=N'test3';
GO

Now you have 60 seconds to check the current execution status for these jobs. To do that you can use the msdb.dbo.sp_help_job procedure or open SSMS Job Activity Monitor.

Job Activity Monitor

In the Job Activity Monitor you can very easily spot that two jobs have the ‘Executing’ status and the third one is waiting for a worker thread.

If you use msdb.dbo.sp_help_job procedure, then you will find execution status in current_execution_status column.

Current Execution Status

Execution Status Description
1 Executing
2 Waiting for thread
3 Between retries
4 Idle
5 Suspended
6 This value is obsolete
7 Performing completion actions
SQL Server Agent Subsystems configuration

To check why only two PowerShell jobs are running you need to take a look on SQL Server Agent Subsystems configuration. Use the below query to do that.

SELECT  s.subsystem_id, 
        s.subsystem, 
        m.[text] AS [description], 
        s.max_worker_threads
FROM msdb.dbo.syssubsystems s
INNER JOIN msdb.sys.messages m 
    ON  s.description_id = m.message_id 
        AND m.language_id = 1033 --English

Results:

Agent Subsystems Max Worker Threads

That explains everything. It turns out that by default it is configured to have only two worker threads for PowerShell jobs’ steps.

The Solution

To fix this issue and allow SQL Server Agent to run more PowerShell steps at the same time you need to change this configuration. You can do it very easily with a simple UPDATE statement. I will change the maximum worker threads threshold to 5. That should be enough for my needs. You need to choose the threshold that will work for you.

UPDATE msdb.dbo.syssubsystems
SET max_worker_threads = 5
WHERE subsystem_id = 12

Agent Subsystems Max Worker Threads after change

To bring this change to life you have to restart the SQL Server Agent service. After that, you can test if this works.

EXEC msdb.dbo.sp_start_job @job_name=N'test1';
EXEC msdb.dbo.sp_start_job @job_name=N'test2';
EXEC msdb.dbo.sp_start_job @job_name=N'test3';
GO

Last look at SSMS Job Activity Monitor.

Job Activity Monitor after change

Cleanup
USE [msdb]
GO

-- DROP Temporary Store Procedure
DROP PROCEDURE #temp_CreateJob;
GO

-- DROP SQL Server Agent Jobs
EXEC msdb.dbo.sp_delete_job  @job_name=N'test1';
EXEC msdb.dbo.sp_delete_job  @job_name=N'test2';
EXEC msdb.dbo.sp_delete_job  @job_name=N'test3';
GO

-- Restore default value
UPDATE msdb.dbo.syssubsystems
SET max_worker_threads = 2
WHERE subsystem_id = 12
GO

Thanks for reading!

-Marek

Share it:
Facebooktwittergoogle_plusredditpinterestlinkedintumblrmailFacebooktwittergoogle_plusredditpinterestlinkedintumblrmail

Leave a Reply

Your email address will not be published. Required fields are marked *