Quartz.Plugins
4.0.0-alpha.1
Prefix Reserved
See the version list below for details.
dotnet add package Quartz.Plugins --version 4.0.0-alpha.1
NuGet\Install-Package Quartz.Plugins -Version 4.0.0-alpha.1
<PackageReference Include="Quartz.Plugins" Version="4.0.0-alpha.1" />
<PackageVersion Include="Quartz.Plugins" Version="4.0.0-alpha.1" />
<PackageReference Include="Quartz.Plugins" />
paket add Quartz.Plugins --version 4.0.0-alpha.1
#r "nuget: Quartz.Plugins, 4.0.0-alpha.1"
#:package Quartz.Plugins@4.0.0-alpha.1
#addin nuget:?package=Quartz.Plugins&version=4.0.0-alpha.1&prerelease
#tool nuget:?package=Quartz.Plugins&version=4.0.0-alpha.1&prerelease
title: Plugins
Quartz.Plugins provides some useful ready-made plugins for your convenience.
Quartz provides an interface (ISchedulerPlugin, in the Quartz.Extensibility namespace) for plugging-in additional functionality.
The plugins that ship in this package live in the Quartz.Plugins.* namespaces — Quartz.Plugins.History,
Quartz.Plugins.Interrupt, Quartz.Plugins.Json, Quartz.Plugins.Management and Quartz.Plugins.Xml, matching the
assembly and NuGet package name. In 3.x they were the singular Quartz.Plugin.*; a quartz.plugin.<name>.type
naming the old spelling still resolves, with a warning.
They provide functionality such as auto-scheduling of jobs upon scheduler startup, logging a history of job and trigger events,
and ensuring that the scheduler shuts down cleanly when the process exits.
Installation
You need to add NuGet package reference to your project which uses Quartz.
dotnet add package Quartz.Plugins
Configuration
Every plugin in this package has an extension method that adds and configures it in one call. That is the
way to reach for; the flat keys, in the format quartz.plugin.{name-to-refer-with}.{property}, are the 3.x
spelling of the same thing and still work.
| Plugin | Extension | Options |
|---|---|---|
LoggingJobHistoryPlugin |
UseJobHistoryLogging(…) |
JobHistoryLoggingOptions |
LoggingTriggerHistoryPlugin |
UseTriggerHistoryLogging(…) |
TriggerHistoryLoggingOptions |
StructuredLoggingJobHistoryPlugin |
UseStructuredJobLogging(…) |
JobHistoryLoggingOptions |
StructuredLoggingTriggerHistoryPlugin |
UseStructuredTriggerLogging(…) |
TriggerHistoryLoggingOptions |
ShutdownHookPlugin |
UseShutdownHook(…) |
ShutdownHookOptions |
XmlSchedulingDataProcessorPlugin |
UseXmlSchedulingConfiguration(…) |
FileSchedulingOptions |
JsonSchedulingDataProcessorPlugin |
UseJsonSchedulingConfiguration(…) |
FileSchedulingOptions |
JobInterruptMonitorPlugin |
UseJobAutoInterrupt(…) |
JobAutoInterruptOptions |
They hang off IQuartzBuilder, so they work the same under AddQuartz and on a standalone
QuartzSchedulerBuilder. See the
configuration reference for how a plugin
is registered and named.
Features
LoggingJobHistoryPlugin
Logs a history of all job executions (and execution vetoes) and writes the entries to configured logging
infrastructure. LoggingTriggerHistoryPlugin does the same for trigger firings, misfires and completions.
services.AddQuartz(q =>
{
q.UseJobHistoryLogging(options =>
{
// each message left unset keeps the plugin's own default
options.JobSuccessMessage = "Job {1}.{0} completed";
});
q.UseTriggerHistoryLogging();
});
Both use index-based placeholders in their messages. Prefer the structured plugins below unless you have existing message templates to keep.
StructuredLoggingJobHistoryPlugin
Structured logging alternative to LoggingJobHistoryPlugin. Uses named message template parameters (e.g. {JobName}, {TriggerGroup}) instead of index-based placeholders, making log output compatible with structured logging sinks like Serilog and NLog. This avoids template cache memory leaks that can occur with the original plugin.
Message templates can be customized via properties. When customizing, the parameter names in templates are positionally mapped, so they must appear in the same order as the defaults.
Available template properties:
| Property | Parameters (in order) |
|---|---|
JobToBeFiredMessage |
{JobGroup}, {JobName}, {TriggerGroup}, {TriggerName}, {FireTime}, {ScheduledFireTime}, {NextFireTime}, {RefireCount} |
JobSuccessMessage |
{JobGroup}, {JobName}, {FireTime}, {TriggerGroup}, {TriggerName}, {Result} |
JobFailedMessage |
{JobGroup}, {JobName}, {FireTime}, {TriggerGroup}, {TriggerName}, {ExceptionMessage} |
JobWasVetoedMessage |
{JobGroup}, {JobName}, {TriggerGroup}, {TriggerName}, {FireTime} |
DI configuration:
services.AddQuartz(q =>
{
q.UseStructuredJobLogging(options =>
{
// Optional; each template left unset keeps the plugin's own default.
options.JobFailedMessage = "Job {JobGroup}.{JobName} failed: {ExceptionMessage}";
});
});
::: tip
Recommended over LoggingJobHistoryPlugin when using structured logging providers (Serilog, NLog, etc.).
:::
StructuredLoggingTriggerHistoryPlugin
Structured logging alternative to LoggingTriggerHistoryPlugin. Logs trigger firings, misfires, and completions using named message template parameters for structured logging compatibility.
Message templates can be customized via properties. When customizing, the parameter names in templates are positionally mapped, so they must appear in the same order as the defaults.
Available template properties:
| Property | Parameters (in order) |
|---|---|
TriggerFiredMessage |
{TriggerGroup}, {TriggerName}, {JobGroup}, {JobName}, {FireTime}, {ScheduledFireTime}, {NextFireTime}, {RefireCount} |
TriggerMisfiredMessage |
{TriggerGroup}, {TriggerName}, {JobGroup}, {JobName}, {FireTime}, {ScheduledFireTime}, {NextFireTime} |
TriggerCompleteMessage |
{TriggerGroup}, {TriggerName}, {JobGroup}, {JobName}, {CompletedTime}, {ScheduledFireTime}, {NextFireTime}, {TriggerInstructionCode} |
DI configuration:
services.AddQuartz(q =>
{
q.UseStructuredTriggerLogging(options =>
{
// Optional; each template left unset keeps the plugin's own default.
options.TriggerMisfiredMessage = "Trigger {TriggerGroup}.{TriggerName} misfired at {FireTime}";
});
});
::: tip
Recommended over LoggingTriggerHistoryPlugin when using structured logging providers (Serilog, NLog, etc.).
:::
ShutdownHookPlugin
This plugin catches the event of the process terminating (such as upon a Ctrl-C) and tells the scheduler to shut down.
services.AddQuartz(q => q.UseShutdownHook(options => options.CleanShutdown = true));
CleanShutdown decides whether the shutdown waits for jobs that are still running. Under a host,
the hosted service already stops the scheduler with the application, so
this plugin is for a scheduler that has no host to stop it.
XmlSchedulingDataProcessorPlugin
This plugin loads XML file(s) to add jobs and schedule them with triggers as the scheduler is initialized, and can optionally periodically scan the file for changes.
services.AddQuartz(q =>
{
q.UseXmlSchedulingConfiguration(x =>
{
x.Files.Add("~/quartz_jobs.config");
x.ScanInterval = TimeSpan.FromMinutes(1);
x.FailOnFileNotFound = true;
x.FailOnSchedulingError = true;
});
});
::: warning The periodically scanning of files for changes is not currently supported in a clustered environment. :::
JsonSchedulingDataProcessorPlugin
This plugin loads JSON file(s) to add jobs and schedule them with triggers as the scheduler is initialized, and can optionally periodically scan the file for changes. It is the JSON analog of XmlSchedulingDataProcessorPlugin.
::: warning The periodically scanning of files for changes is not currently supported in a clustered environment. :::
DI configuration:
services.AddQuartz(q =>
{
q.UseJsonSchedulingConfiguration(x =>
{
x.Files.Add("quartz_jobs.json");
x.ScanInterval = TimeSpan.FromMinutes(1);
x.FailOnFileNotFound = true;
x.FailOnSchedulingError = true;
});
});
See JSON Configuration for the full JSON file format and trigger type reference.
JobInterruptMonitorPlugin
This plugin catches the event of job running for a long time (more than the configured max time) and tells the scheduler to "try" interrupting it if enabled.
services.AddQuartz(q => q.UseJobAutoInterrupt(options =>
{
// the default, applied to every job that opts in
options.DefaultMaxRunTime = TimeSpan.FromMinutes(5);
}));
Each job configuration needs to have JobInterruptMonitorPlugin.JobDataMapKeyAutoInterruptable key's value set to true in order for plugin to monitor the execution timeout.
Jobs can also define custom timeout value instead of global default by using key JobInterruptMonitorPlugin.JobDataMapKeyMaxRunTime.
IJobDetail job = JobBuilder.Create<SlowJob>()
.WithIdentity("slowJob")
.UsingJobData(JobInterruptMonitorPlugin.JobDataMapKeyAutoInterruptable, true)
// allow only five seconds for this job, overriding default configuration.
// the value is milliseconds, and either a number or a string holding one works
.UsingJobData(JobInterruptMonitorPlugin.JobDataMapKeyMaxRunTime, "5000")
.Build();
Both AutoInterruptable and MaxRunTime are read from the merged job data map, so a trigger's data map can also enable interruption or override the timeout for its own fires.
Only the execution that exceeded its allowed run time is interrupted — the plugin monitors each fire instance separately, so concurrent executions of the same job are unaffected. Executions vetoed by a trigger listener do not arm the interrupt timer.
Adding a plugin
AddPlugin comes in the same three shapes as the listener registrations: the container builds the
plugin, you build it, or you configure options it is given.
services.AddQuartz(q =>
{
// the container constructs it, so it gets constructor injection
q.AddPlugin<MyPlugin>();
// you construct it
q.AddPlugin(provider => new MyPlugin(provider.GetRequiredService<IMyPluginDependency>()));
// it takes an IOptions<MyPluginOptions> of its own
q.AddPlugin<MyPlugin, MyPluginOptions>(options => options.SomeSetting = "value");
});
Every shape takes an optional name as its last argument:
q.AddPlugin<MyPlugin>("myPlugin");
q.AddPlugin(provider => new MyPlugin(), "myPlugin");
q.AddPlugin<MyPlugin, MyPluginOptions>(options => options.SomeSetting = "value", "myPlugin");
The name is how the scheduler refers to the plugin, and some plugins derive persisted job and trigger
keys from it — so it is part of the deployment's identity rather than a label. It is also the name a
quartz.plugin.{name}.* key configures the same plugin under, which is what lets a plugin added in
code be configured from a file. Left unset, the plugin's type name is used. The plugins shipped with
Quartz use their conventional short names (xml, json, jobHistory, …) for that reason.
The options of the third shape belong to the scheduler they were added to, like every other
per-scheduler setting: two schedulers can add the same plugin with the same options type and each
plugin sees its own configuration. They are named options under the scheduler's name, so a plugin on
services.AddQuartz("reporting", …) is configured by services.Configure<MyPluginOptions>("reporting", …)
as well — a plain services.Configure<MyPluginOptions>(…) configures the default scheduler's.
Take them as IOptions<MyPluginOptions> for a fixed value, or as IOptionsMonitor<MyPluginOptions>
to follow a reloading configuration source. CurrentValue is your scheduler's instance, Get(name)
is whichever instance you name, and OnChange fires for your scheduler's options only — so a plugin
watching for changes is never handed a sibling scheduler's configuration as though it were its own.
Authoring plugin configuration extensions
When you write your own ISchedulerPlugin, offer the same experience as the built-in plugins with an
extension method on IQuartzBuilder. Take an options object of your own, apply it to the plugin, and
register the plugin under its conventional name:
public static class MyPluginConfigurationExtensions
{
public static IQuartzBuilder UseMyPlugin(
this IQuartzBuilder builder,
Action<MyPluginOptions>? configure = null)
{
ArgumentNullException.ThrowIfNull(builder);
var options = new MyPluginOptions();
configure?.Invoke(options);
// companion services your plugin needs injected
builder.Services.TryAddSingleton<IMyPluginDependency, MyPluginDependency>();
return builder.AddPlugin<MyPlugin>(
provider =>
{
var plugin = ActivatorUtilities.CreateInstance<MyPlugin>(provider);
plugin.SomeSetting = options.SomeSetting;
return plugin;
},
name: "myPlugin");
}
}
public sealed class MyPluginOptions
{
public string? SomeSetting { get; set; }
}
The same extension method works wherever an IQuartzBuilder does, which is both configuration styles:
// under a host
services.AddQuartz(q => q.UseMyPlugin(options => options.SomeSetting = "value"));
// standalone, without an application container
var builder = QuartzSchedulerBuilder.Create();
builder.UseMyPlugin(options => options.SomeSetting = "value");
var scheduler = await builder.BuildScheduler();
Configuration written this way and configuration written as quartz.plugin.myPlugin.someSetting
reach the same plugin instance, because they agree on its name: the properties are applied to the
plugin the code registered rather than building a second copy of it.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.DependencyInjection (>= 10.0.11)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.11)
- Microsoft.Extensions.Logging (>= 10.0.11)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.11)
- Quartz.Jobs (>= 4.0.0-alpha.1)
NuGet packages (29)
Showing the top 5 NuGet packages that depend on Quartz.Plugins:
| Package | Downloads |
|---|---|
|
Castle.Facilities.Quartz
Castle Windsor Quartz facility lets you easily add windsor to Quartz apps. |
|
|
Quartz.HostedService
Use .Net Core Generic Service and Quartz to Implement Background Schedule Tasks. |
|
|
Grebok.AspNet
Grebok Framework |
|
|
Excalibur.Jobs
Consolidated Excalibur job scheduling and orchestration framework. Includes abstractions, core implementations, coordination, workflows, and Quartz integration. |
|
|
Excalibur.Hosting.Jobs
Job hosting infrastructure for Excalibur applications with .NET Worker Service and Web hosting support. |
GitHub repositories (5)
Showing the top 5 popular GitHub repositories that depend on Quartz.Plugins:
| Repository | Stars |
|---|---|
|
foxminchan/BookWorm
The practical implementation of Aspire using Microservices, AI-Agents
|
|
|
withsalt/BilibiliLiveTools
Bilibili(B站)无人值守直播工具。自动登录,自动获取直播推流地址,自动推流(使用ffmpeg),可以用于电脑、树莓派等设备无人值守直播。
|
|
|
guoming/Hummingbird
分布式锁,分布式ID,分布式消息队列、配置中心、注册中心、服务注册发现、超时、重试、熔断、负载均衡
|
|
|
microsoft/Recurring-Integrations-Scheduler
Recurring Integrations Scheduler (RIS) is a solution that can be used in file-based integration scenarios for Dynamics 365 Finance and Dynamics 365 Supply Chain Management.
|
|
|
oncemi/OnceMi.Framework
基于.NET 7和Vue 2开发的企业级前后端分离权限管理开发框架(后台管理系统),具有组织管理、角色管理、用户管理、菜单管理、授权管理、计划任务、文件管理等功能。支持国内外多种流行数据库,支持IdentityServer4认证中心。
|
| Version | Downloads | Last Updated |
|---|---|---|
| 4.0.0-alpha.2 | 35 | 8/25/2026 |
| 4.0.0-alpha.1 | 64 | 8/22/2026 |
| 3.19.1 | 19,345 | 7/26/2026 |
| 3.19.0 | 8,514 | 7/24/2026 |
| 3.18.2 | 32,165 | 6/27/2026 |
| 3.18.1 | 106,895 | 4/25/2026 |
| 3.18.0 | 36,632 | 4/11/2026 |
| 3.17.1 | 13,407 | 4/3/2026 |
| 3.17.0 | 6,372 | 3/29/2026 |
| 3.16.1 | 49,797 | 3/4/2026 |
| 3.16.0 | 3,847 | 3/1/2026 |
| 3.15.1 | 163,955 | 10/26/2025 |
| 3.15.0 | 99,033 | 8/3/2025 |
| 3.14.0 | 384,167 | 3/8/2025 |
| 3.13.1 | 337,369 | 11/2/2024 |
| 3.13.0 | 149,683 | 8/10/2024 |
| 3.12.0 | 25,297 | 8/3/2024 |
| 3.11.0 | 94,299 | 7/7/2024 |
| 3.10.0 | 42,578 | 6/26/2024 |
| 3.9.0 | 557,062 | 5/9/2024 |