Class QuartzHealthCheckOptions
- Namespace
- Quartz
- Assembly
- Quartz.dll
Options for the Quartz scheduler health check registered by AddQuartz(IHealthChecksBuilder, Action<QuartzHealthCheckOptions>?) and by AddQuartzHealthChecks(IQuartzBuilder, Action<QuartzHealthCheckOptions>?).
public sealed class QuartzHealthCheckOptions
- Inheritance
-
QuartzHealthCheckOptions
- Inherited Members
Examples
options.RequireSuccessWithin(new JobKey("nightly-report", "reports"), TimeSpan.FromHours(26));
Properties
ClusterCheckinTolerance
How many of its own check-in intervals a clustered node may go without checking in before the
check reports Degraded. 3 by default; null
or 0 turns the reading off.
public double? ClusterCheckinTolerance { get; set; }
Property Value
Remarks
The rest of this check asserts that the scheduler can fire and that its store answers. Neither says anything about the cluster manager, which runs on its own timer: a node whose check-in loop has wedged still answers a store query, still reports Running, and is meanwhile being recovered by its peers — they take its triggers because it looks dead to them, while its own probe says it is fine.
So a clustered scheduler is also asked when it last checked in, through SchedulerQueryExtensions' cluster listing, and a last check-in older than this many of the node's own configured intervals is reported as degraded rather than healthy. Three because that is the same order of magnitude cluster recovery uses to decide a node is gone — one interval is an ordinary scheduling delay, and a node that has missed three is not merely late.
The reading happens only when the store says it is clustered, so a scheduler on an in-memory or
unclustered store makes no extra query. Set this to null or 0 to make
no query at all.
FailureStatus
The HealthStatus reported when the check fails. When null the default (Unhealthy) is used.
public HealthStatus? FailureStatus { get; set; }
Property Value
Name
The name used to register the health check.
public string? Name { get; set; }
Property Value
Remarks
Left unset, the check is called quartz-scheduler, or
quartz-scheduler-<scheduler name> for a named scheduler — which is why it is
nullable rather than carrying one of those as its value: the name depends on which scheduler the
check is for, and that is not known to an options object.
RequiredJobs
Jobs that must have succeeded recently. Empty by default, which reads nothing.
public List<RequiredJobOptions> RequiredJobs { get; }
Property Value
Remarks
A requirement is met while the job's LastSucceededAtUtc is within its SucceededWithin of now, on the scheduler's clock; a skipped run counts as a success. A job with no recorded success is judged from the first time the check evaluated it, so one that has not run within its window since then fails. A job that is not met reports its Status, and the check reports the worst of that and the scheduler's own verdict. The report's data carries one entry per job that is not met.
The statuses are read from the scheduler's execution history, in one QueryJobRunStatuses(JobRunStatusQuery, CancellationToken) per check. A scheduler with no history, or a history that keeps no status, fails validation at startup.
One requirement per job: when a job is listed twice, the later entry wins. Get-only, like every collection on a Quartz options type, so a configuration section binds into it; add to it, or call RequireSuccessWithin(JobKey, TimeSpan, HealthStatus).
StaleFiringTolerance
How many of the store's own misfire thresholds a trigger may be overdue before the check reports
Degraded, and half of how many before it reports
Unhealthy. null by default, which turns the
reading off; 0 does the same. 3 is the value to start from.
public double? StaleFiringTolerance { get; set; }
Property Value
Remarks
This is the silent stall: nothing has fired for a while although something should have. A scheduler in that state passes everything else this check asks — it is Running, its store answers, its cluster manager may well still be checking in — because none of those questions is about work actually leaving the queue. A wedged scheduler thread, a thread pool with nothing free, a lock nobody releases and a job store whose acquisition query has begun timing out all look identical from outside and all look healthy.
So the check asks the store for a trigger that is schedulable (Normal) and whose next fire time has passed by more than this many misfire thresholds. Finding one means the scheduler is late by more than lateness is defined to be; finding one twice as late is reported as unhealthy, because a backlog that keeps growing is no longer a delay. The overdue trigger's key and the instant it was due are in the report's data, so an operator sees which trigger is waiting and since when.
The misfire threshold is the unit because it is the store's own definition of "late enough to
matter" — MisfireThreshold or
MisfireThreshold, whichever this scheduler runs, and one
minute for a store that has neither. It is also, on the database store, the default sweep
interval of the misfire handler, which is why the multiplier has to be more than one: a trigger
can be a threshold late before it counts as misfired and another sweep late before the handler
reaches it, so anything under 3 can report ordinary recovery as a stall.
Off by default, unlike ClusterCheckinTolerance, because what counts as overdue is the application's to say: a scheduler whose triggers are deliberately paused-by-calendar, or one that is meant to run a backlog down after a maintenance window, is not stalled. A standby or paused scheduler is never read this way at all — those are deliberate, and the check reports them as it always has.
StandbyStatus
The HealthStatus reported while the scheduler is in Standby. When null the default (Degraded) is used.
public HealthStatus? StandbyStatus { get; set; }
Property Value
Remarks
Degraded is the right default and the wrong answer for some deployments. Standby is deliberate
and reversible, so calling it healthy would hide an application that never started its
scheduler and calling it unhealthy would take a node out of rotation for doing what it was
told. But a report is only read by whoever it reaches: an ASP.NET Core application can remap
degraded on the endpoint with MapHealthChecks(…, new HealthCheckOptions { ResultStatusCodes
= … }), while a worker has no endpoint at all — its only reader is the probe that asks the
HealthCheckService directly, and a standby node it must not route to has to say
Unhealthy here.
This is the standby verdict alone. A scheduler still in Created because AutoStart is false also reports degraded, and keeps doing so: that is a window between the host starting and the application pressing start, not a state a node sits in.
Tags
Tags associated with the health check, allowing it to be filtered (for example into separate liveness and readiness probes).
public List<string> Tags { get; }
Property Value
Remarks
Get-only with an in-place initializer, like every other collection on a Quartz options type: a
configuration binder binds into a non-null collection without needing a setter, and one
configure callback cannot discard the tags another added. Add to it —
options.Tags.Add("ready") — rather than assigning a new collection.
UnservedExecutionGroupTolerance
How many of the store's own misfire thresholds a schedulable trigger in an execution group this
node does not serve may be overdue before the check reports
Degraded. 3 by default; null or 0
turns the reading off.
public double? UnservedExecutionGroupTolerance { get; set; }
Property Value
Remarks
The trap in routing a group to some nodes: when none of them is live, nothing acquires the group's triggers and — because a node's misfire sweep handles only the groups it serves — nothing re-arms them either. They wait, unmodified, and from a node that does not serve them that is invisible unless something looks. So a node whose ServedExecutionGroups or RefusedExecutionGroups is set asks the store for the schedulable triggers overdue by more than this many misfire thresholds, and reports the groups among them it does not serve, with a count each and the oldest fire time.
Three, for the reason StaleFiringTolerance suggests it: a serving node's sweep re-arms a misfired trigger within about a threshold of it crossing the line, so one overdue by three has had no serving node's sweep reach it. Degraded rather than unhealthy, because the reporting node is fine and taking it out of rotation helps nobody. A node that routes nothing makes no query.
Methods
RequireSuccessWithin(JobKey, TimeSpan, HealthStatus)
Requires job to have succeeded within within, replacing any
requirement already given for it.
public void RequireSuccessWithin(JobKey job, TimeSpan within, HealthStatus status = HealthStatus.Degraded)
Parameters
jobJobKeyThe job.
withinTimeSpanHow long ago its last success may have fired. Must be positive.
statusHealthStatusWhat the check reports while the requirement is not met: Degraded or Unhealthy.