Quartz 3.13.0

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package Quartz --version 3.13.0                
NuGet\Install-Package Quartz -Version 3.13.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Quartz" Version="3.13.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Quartz --version 3.13.0                
#r "nuget: Quartz, 3.13.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Quartz as a Cake Addin
#addin nuget:?package=Quartz&version=3.13.0

// Install Quartz as a Cake Tool
#tool nuget:?package=Quartz&version=3.13.0                

layout: default title: Quartz.NET Quick Start Guide

Welcome to the Quick Start Guide for Quartz.NET. As you read this guide, expect to see details of:

  • Downloading Quartz.NET
  • Installing Quartz.NET
  • Configuring Quartz to your own particular needs
  • Starting a sample application

Download and Install

You can either download the zip file or use the NuGet package. NuGet package contains only the binaries needed to run Quartz.NET, zip file comes with source code, samples and Quartz.NET server sample application.

NuGet Package

Couldn't get any simpler than this. Just fire up Visual Studio (with NuGet installed) and add reference to package Quartz from package manager extension:

  • Right-click on your project's References and choose Manage NuGet Packages...
  • Choose Online category from the left
  • Enter Quartz to the top right search and hit enter
  • Choose Quartz.NET from search results and hit install
  • Done!

or from NuGet Command-Line:

Install-Package Quartz

If you want to add JSON Serialization, just add the Quartz.Serialization.Json package the same way.

Zip Archive

Short version: Once you've downloaded Quartz.NET, unzip it somewhere, grab the Quartz.dll from bin directory and start to use it.

Quartz core library does not have any hard binary dependencies. You can opt-in to more dependencies when you choose to use JSON serialization package, which requires JSON.NET. You need to have at least Quartz.dll beside your app binaries to successfully run Quartz.NET. So just add it as a references to your Visual Studio project that uses them. You can find these dlls from extracted archive from path bin\your-target-framework-version\release\Quartz.

Configuration

This is the big bit! Quartz.NET is a very configurable library. There are two main ways (which are not mutually exclusive) to supply Quartz.NET configuration information:

Fluent Scheduler Builder API

You can configure scheduler using C# fluent API, or via providing NameValueCollection parameter to scheduler factory which contains configuration keys and values.

// you can have base properties
var properties = new NameValueCollection();

// and override values via builder
IScheduler scheduler = await SchedulerBuilder.Create(properties)
    // default max concurrency is 10
    .UseDefaultThreadPool(x => x.MaxConcurrency = 5)
    // this is the default 
    // .WithMisfireThreshold(TimeSpan.FromSeconds(60))
    .UsePersistentStore(x =>
    {
        // force job data map values to be considered as strings
        // prevents nasty surprises if object is accidentally serialized and then 
        // serialization format breaks, defaults to false
        x.UseProperties = true;
        x.UseClustering();
        // there are other SQL providers supported too 
        x.UseSqlServer("my connection string");
        // this requires Quartz.Serialization.Json NuGet package
        x.UseJsonSerializer();
    })
    // job initialization plugin handles our xml reading, without it defaults are used
    // requires Quartz.Plugins NuGet package
    .UseXmlSchedulingConfiguration(x =>
    {
        x.Files = new[] { "~/quartz_jobs.xml" };
        // this is the default
        x.FailOnFileNotFound = true;
        // this is not the default
        x.FailOnSchedulingError = true;
    })
    .BuildScheduler();

await scheduler.Start();

Configuration files

Following files are searched for known configuration properties:

  • YourApplication.exe.config configuration file using quartz-element (full .NET framework only)
  • appsettings.json (.NET Core/NET5 onwards)
  • quartz.config file in your application's root directory (works both with .NET Core and full .NET Framework)

Full documentation of available properties is available in the Quartz Configuration Reference.

To get up and running quickly, a basic quartz.config looks something like this:

quartz.scheduler.instanceName = MyScheduler
quartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz
quartz.threadPool.maxConcurrency = 3

Remember to set the Copy to Output Directory on Visual Studio's file property pages to have value Copy always. Otherwise the config will not be seen if it's not in build directory.

The scheduler created by this configuration has the following characteristics:

  • quartz.scheduler.instanceName - This scheduler's name will be "MyScheduler".

  • quartz.threadPool.maxConcurrency - Maximum of 3 jobs can be run simultaneously (default is 10).

  • quartz.jobStore.type - All of Quartz's data, such as details of jobs and triggers, is held in memory (rather than in a database).

  • Even if you have a database and want to use it with Quartz, I suggest you get Quartz working with the RamJobStore before you open up a whole new dimension by working with a database.

::: tip Actually you don't need to define these properties if you don't want to, Quartz.NET comes with sane defaults :::

Starting a Sample Application

Now you've downloaded and installed Quartz, it's time to get a sample application up and running. The following code obtains an instance of the scheduler, starts it, then shuts it down:

Program.cs

using System;
using System.Threading.Tasks;

using Quartz;
using Quartz.Impl;

namespace QuartzSampleApp
{
    public class Program
    {
        private static async Task Main(string[] args)
        {
            // Grab the Scheduler instance from the Factory
            StdSchedulerFactory factory = new StdSchedulerFactory();
            IScheduler scheduler = await factory.GetScheduler();

            // and start it off
            await scheduler.Start();

            // some sleep to show what's happening
            await Task.Delay(TimeSpan.FromSeconds(10));

            // and last shut down the scheduler when you are ready to close your program
            await scheduler.Shutdown();
        }
    }
}

As of Quartz 3.0 your application will terminate when there's no code left to execute after scheduler.Shutdown(), because there won't be any active threads. You should manually block exiting of application if you want scheduler to keep running also after the Task.Delay and Shutdown has been processed.

Now running the program will not show anything. When 10 seconds have passed the program will just terminate. Lets add some logging to console.

Adding logging

LibLog can be configured to use different logging frameworks under the hood; namely Log4Net, NLog and Serilog.

When LibLog does not detect any other logging framework to be present, it will be silent. We can configure a custom logger provider that just logs to console show the output if you don't have logging framework setup ready yet.

LogProvider.SetCurrentLogProvider(new ConsoleLogProvider());

private class ConsoleLogProvider : ILogProvider
{
    public Logger GetLogger(string name)
    {
        return (level, func, exception, parameters) =>
        {
            if (level >= LogLevel.Info && func != null)
            {
                Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters);
            }
            return true;
        };
    }

    public IDisposable OpenNestedContext(string message)
    {
        throw new NotImplementedException();
    }

    public IDisposable OpenMappedContext(string key, object value, bool destructure = false)
    {
        throw new NotImplementedException();
    }
}

Trying out the application

Now we should get a lot more information when we start the application.

[12.51.10] [Info] Quartz.NET properties loaded from configuration file 'C:\QuartzSampleApp\quartz.config'
[12.51.10] [Info] Initialized Scheduler Signaller of type: Quartz.Core.SchedulerSignalerImpl
[12.51.10] [Info] Quartz Scheduler created
[12.51.10] [Info] RAMJobStore initialized.
[12.51.10] [Info] Scheduler meta-data: Quartz Scheduler (v3.0.0.0) 'MyScheduler' with instanceId 'NON_CLUSTERED'
  Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool 'Quartz.Simpl.DefaultThreadPool' - with 3 threads.
  Using job-store 'Quartz.Simpl.RAMJobStore' - which does not support persistence. and is not clustered.

[12.51.10] [Info] Quartz scheduler 'MyScheduler' initialized
[12.51.10] [Info] Quartz scheduler version: 3.0.0.0
[12.51.10] [Info] Scheduler MyScheduler_$_NON_CLUSTERED started.

We need a simple test job to test the functionality, lets create HelloJob that outputs greetings to console.

public class HelloJob : IJob
{
	public async Task Execute(IJobExecutionContext context)
	{
		await Console.Out.WriteLineAsync("Greetings from HelloJob!");
	}
}

To do something interesting, you need code just after Start() method, before the Task.Delay.

// define the job and tie it to our HelloJob class
IJobDetail job = JobBuilder.Create<HelloJob>()
	.WithIdentity("job1", "group1")
	.Build();

// Trigger the job to run now, and then repeat every 10 seconds
ITrigger trigger = TriggerBuilder.Create()
	.WithIdentity("trigger1", "group1")
	.StartNow()
	.WithSimpleSchedule(x => x
		.WithIntervalInSeconds(10)
		.RepeatForever())
	.Build();

// Tell quartz to schedule the job using our trigger
await scheduler.ScheduleJob(job, trigger);

// You could also schedule multiple triggers for the same job with
// await scheduler.ScheduleJob(job, new List<ITrigger>() { trigger1, trigger2 }, replace: true);

The complete console application will now look like this

using System;
using System.Threading.Tasks;

using Quartz;
using Quartz.Impl;
using Quartz.Logging;

namespace QuartzSampleApp
{
    public class Program
    {
        private static async Task Main(string[] args)
        {
            LogProvider.SetCurrentLogProvider(new ConsoleLogProvider());

            // Grab the Scheduler instance from the Factory
            StdSchedulerFactory factory = new StdSchedulerFactory();
            IScheduler scheduler = await factory.GetScheduler();

            // and start it off
            await scheduler.Start();

            // define the job and tie it to our HelloJob class
            IJobDetail job = JobBuilder.Create<HelloJob>()
                .WithIdentity("job1", "group1")
                .Build();

            // Trigger the job to run now, and then repeat every 10 seconds
            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity("trigger1", "group1")
                .StartNow()
                .WithSimpleSchedule(x => x
                    .WithIntervalInSeconds(10)
                    .RepeatForever())
                .Build();

            // Tell quartz to schedule the job using our trigger
            await scheduler.ScheduleJob(job, trigger);

            // some sleep to show what's happening
            await Task.Delay(TimeSpan.FromSeconds(60));

            // and last shut down the scheduler when you are ready to close your program
            await scheduler.Shutdown();

            Console.WriteLine("Press any key to close the application");
            Console.ReadKey();
        }

        // simple log provider to get something to the console
        private class ConsoleLogProvider : ILogProvider
        {
            public Logger GetLogger(string name)
            {
                return (level, func, exception, parameters) =>
                {
                    if (level >= LogLevel.Info && func != null)
                    {
                        Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters);
                    }
                    return true;
                };
            }

            public IDisposable OpenNestedContext(string message)
            {
                throw new NotImplementedException();
            }

            public IDisposable OpenMappedContext(string key, object value, bool destructure = false)
            {
                throw new NotImplementedException();
            }
        }
    }

    public class HelloJob : IJob
    {
        public async Task Execute(IJobExecutionContext context)
        {
            await Console.Out.WriteLineAsync("Greetings from HelloJob!");
        }
    }
}

Creating and initializing database

In order to use SQL persistence storage for Quartz and enabling features like clustering, you need to create a database and initialize the schema objects using SQL scripts. First you need to create a database and credentials for Quartz. After you have a database that Quartz will be able to connect to, you also need to create database tables and indexes that Quartz needs for successful operation.

You can find latest DDL scripts in Quartz's GitHub repository and they are also contained in the ZIP archive distribution. There are also thirty party additions to Quartz that enable other types of storage, like NoSQL databases. You can search for them on NuGet.

Now go have some fun exploring Quartz.NET! You can continue by reading the tutorial.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 is compatible.  net463 was computed.  net47 was computed.  net471 was computed.  net472 is compatible.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (732)

Showing the top 5 NuGet packages that depend on Quartz:

Package Downloads
Quartz.Extensions.DependencyInjection

Quartz.NET Microsoft.Extensions.DependencyInjection integration; Quartz Scheduling Framework for .NET

Quartz.Serialization.Json

Quartz.NET JSON Serialization Support; Quartz Scheduling Framework for .NET

Quartz.Jobs

Quartz.NET Jobs; Quartz Scheduling Framework for .NET

MassTransit.Quartz

MassTransit Quartz.NET scheduler support; MassTransit provides a developer-focused, modern platform for creating distributed applications without complexity.

Quartz.Plugins.TimeZoneConverter

Quartz.NET TimeZoneConverter integration https://github.com/mj1856/TimeZoneConverter; Quartz Scheduling Framework for .NET

GitHub repositories (89)

Showing the top 5 popular GitHub repositories that depend on Quartz:

Repository Stars
bitwarden/server
Bitwarden infrastructure/backend (API, database, Docker, etc).
abpframework/abp
Open-source web application framework for ASP.NET Core! Offers an opinionated architecture to build enterprise software solutions with best practices on top of the .NET. Provides the fundamental infrastructure, cross-cutting-concern implementations, startup templates, application modules, UI themes, tooling and documentation.
aspnetboilerplate/aspnetboilerplate
ASP.NET Boilerplate - Web Application Framework
kgrzybek/modular-monolith-with-ddd
Full Modular Monolith application with Domain-Driven Design approach.
MassTransit/MassTransit
Distributed Application Framework for .NET
Version Downloads Last updated
3.13.1 12,712 11/2/2024
3.13.0 1,407,616 8/10/2024
3.12.0 216,312 8/3/2024
3.11.0 1,003,523 7/7/2024
3.10.0 296,968 6/26/2024
3.9.0 1,548,442 5/9/2024
3.8.1 2,795,554 2/17/2024
3.8.0 3,521,636 11/18/2023
3.7.0 3,301,201 8/4/2023
3.6.3 1,312,302 6/25/2023
3.6.2 4,922,938 2/25/2023
3.6.1 5,778 2/25/2023 3.6.1 is deprecated because it has critical bugs.
3.6.0 1,295,015 1/29/2023
3.5.0 5,746,365 9/18/2022
3.4.0 8,151,103 3/27/2022
3.3.3 9,924,508 8/1/2021
3.3.2 3,888,921 4/9/2021
3.3.1 78,527 4/8/2021
3.3.0 35,292 4/7/2021
3.2.4 3,540,931 1/19/2021
3.2.3 2,390,825 10/31/2020
3.2.2 527,416 10/19/2020
3.2.1 21,103 10/18/2020
3.2.0 283,288 10/2/2020
3.1.0 1,561,452 7/24/2020
3.0.7 13,753,170 10/7/2018
3.0.6 1,858,547 7/6/2018
3.0.5 476,240 5/27/2018
3.0.4 922,074 3/4/2018
3.0.3 68,796 2/24/2018
3.0.2 452,980 1/25/2018
3.0.1 50,135 1/21/2018
3.0.0 459,947 12/30/2017
2.6.2 1,384,045 5/27/2018
2.6.1 1,523,735 10/9/2017
2.6.0 684,571 7/30/2017
2.5.0 1,430,857 2/18/2017
2.4.1 1,352,842 8/24/2016
2.4.0 90,519 8/18/2016
2.3.3 2,255,152 7/9/2015
2.3.2 736,898 3/30/2015
2.3.1 469,027 1/15/2015
2.3.0 489,916 11/8/2014
2.2.4 677,223 7/27/2014
2.2.3 313,377 3/30/2014
2.2.2 152,091 2/9/2014
2.2.1 140,733 11/24/2013
2.2.0 175,991 9/9/2013
2.1.2 730,758 1/13/2013
2.1.1 9,144 1/4/2013
2.1.0 6,161 12/31/2012
2.0.1 210,067 4/22/2012
2.0.0 31,614 4/9/2012
1.0.3 413,731 8/3/2011