Table of Contents

Interface IThreadPool

Namespace
Quartz.Extensibility
Assembly
Quartz.dll

The interface to be implemented by classes that want to provide a thread pool for the IScheduler's use.

public interface IThreadPool

Remarks

IThreadPool implementation instances should ideally be made for the sole use of Quartz. Most importantly, when the method WaitForAvailableThreads(CancellationToken) returns a value of 1 or greater, there must still be at least one available thread in the pool when the method TryRun(Func<ValueTask>, CancellationToken) is called a few moments (or many moments) later. If this assumption does not hold true, it may result in extra JobStore queries and updates, and if clustering features are being used, it may result in greater imbalance of load.

Properties

PoolSize

Get the current number of threads in the IThreadPool.

int PoolSize { get; }

Property Value

int

Methods

Drain(CancellationToken)

Stops the pool accepting new work, waits for the work already running to finish, and frees the pool's resources.

ValueTask<bool> Drain(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

Cancels the wait, not the running work.

Returns

ValueTask<bool>

true if the work that was running finished; false if cancellationToken fired first and work is still running.

Remarks

The bounded form of Shutdown(bool, CancellationToken) with waitForJobsToComplete: true: the wait ends when cancellationToken fires, and the outcome is reported rather than thrown. That is what lets a caller say "drain, but give up after this long" and still carry on with the rest of its own shutdown — which Shutdown(bool, CancellationToken) cannot express, because a wait it abandoned by throwing would skip everything the caller still has to tear down.

The wait must not block the calling thread. Callers include a host's graceful-shutdown path, and an implementation that blocks pins a thread for as long as the slowest job runs.

Giving up abandons the wait, never the work: running work is not cancelled, because the pool has no means to interrupt it and whether a shutting-down scheduler interrupts its jobs is ShutdownJobInterruption's decision, already made by the time this is called. The pool is left shut down either way, so the answer says what was true when it stopped waiting, not what the caller should do about it.

The barrier has to cover everything a work item does, and not merely the part of it a caller can see: TryRun(Func<ValueTask>, CancellationToken) is handed the whole of a job's execution, of which the last act is the job store update that completes the trigger. A pool that waits for its work items therefore waits for those writes too — which a count of executing jobs does not, since a job leaves that count before its store update is issued.

The default implementation calls Shutdown(bool, CancellationToken) with waitForJobsToComplete: true, whose wait cannot be given up on, and so it can only report that it drained. That keeps a pool written before this member existed correct rather than fast; override it to honour a deadline.

Initialize(CancellationToken)

Must be called before the thread pool is used, in order to give the it a chance to Initialize.

ValueTask Initialize(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

The cancellation instruction.

Returns

ValueTask

Remarks

Typically called by the ISchedulerFactory.

Shutdown(bool, CancellationToken)

Called by the QuartzScheduler to inform the thread pool that it should free up all of it's resources because the scheduler is shutting down.

ValueTask Shutdown(bool waitForJobsToComplete = true, CancellationToken cancellationToken = default)

Parameters

waitForJobsToComplete bool

Whether to wait for executing jobs to finish first.

cancellationToken CancellationToken

The cancellation instruction.

Returns

ValueTask

TryRun(Func<ValueTask>, CancellationToken)

Schedules the given work to run as soon as the pool's concurrency rules allow it.

ValueTask<bool> TryRun(Func<ValueTask> action, CancellationToken cancellationToken = default)

Parameters

action Func<ValueTask>

The work to run.

cancellationToken CancellationToken

The cancellation instruction.

Returns

ValueTask<bool>

true if the work was scheduled; otherwise, false (the pool has been shut down or was never initialized).

Remarks

The implementation of this interface should not throw exceptions unless there is a serious problem (i.e. a serious misconfiguration). If there are no available slots, rather it should either queue the action, or wait until a slot is available, depending on the desired strategy.

WaitForAvailableThreads(CancellationToken)

Determines the number of execution slots that are currently available in the pool. The scheduler uses the count to size the batch of triggers it acquires next.

ValueTask<int> WaitForAvailableThreads(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

The cancellation instruction.

Returns

ValueTask<int>

the number of currently available execution slots

Remarks

The implementation of this method should wait until there is at least one available slot. It is awaited by the scheduler's own loop, so an implementation must not block the calling thread while it waits.