Table of Contents

Class AdoJobStoreOptions

Namespace
Quartz
Assembly
Quartz.dll

Strongly typed configuration for the ADO.NET (persistent) job store.

public sealed class AdoJobStoreOptions
Inheritance
AdoJobStoreOptions
Inherited Members

Remarks

Binds from the JobStore section of the Quartz configuration, and is the typed replacement for the quartz.jobStore.* property keys. Scheduler identity is not repeated here — components that need it inject QuartzSchedulerOptions as well, and neither are the clustering settings, which live once on ClusteringOptions.

Properties

AcceptEnlistedTransactions

Whether the job store may take part in a transaction the application owns, rather than always managing an ADO.NET transaction of its own.

public bool AcceptEnlistedTransactions { get; set; }

Property Value

bool

Remarks

When enabled, the job store uses the connection the application enlisted with EnlistTransaction(IScheduler, DbTransaction) or EnlistConnection(IScheduler, DbConnection, DbTransaction?) for operations on that asynchronous flow, so scheduling either commits with the rest of the application's work or not at all.

Taking part always means handing over a connection. Operations with nothing enlisted keep using a connection of the job store's own, and on the default store — UsePersistentStore(Action<IPersistentStoreBuilder>) without more — that connection is deliberately kept out of any ambient Transaction. The store UseAmbientTransactions() selects is the exception, since running inside a container-managed transaction is that store's contract.

AcquireTriggersWithinLock

Whether trigger acquisition happens inside the database lock.

public bool AcquireTriggersWithinLock { get; set; }

Property Value

bool

CommandTimeout

How long a statement the job store issues may run before the provider cancels it. Left unset, each statement keeps whatever default the ADO.NET provider gives a new command — 30 seconds for most of them.

public TimeSpan? CommandTimeout { get; set; }

Property Value

TimeSpan?

Remarks

This covers every statement the store issues, including the ones the lock handler takes its row lock with, which is where a timeout matters most: a node blocked on QRTZ_LOCKS behind a peer that has stopped without releasing it waits for the provider's default before it can fail and retry, and the scheduling loop is stalled for all of it.

There is deliberately no per-statement override. A timeout that varies by statement is a way of saying some of the store's work is more expendable than the rest, and none of it is: every statement runs inside a lock the rest of the cluster is waiting on.

ADO.NET's CommandTimeout counts whole seconds, so a value is rounded up to the next second — a configured 1500ms is applied as 2 seconds. Rounding up rather than down keeps a sub-second value from becoming zero, which every provider reads as "wait forever".

DataSource

The name of the data source this job store reads and writes through.

public string DataSource { get; set; }

Property Value

string

Remarks

Resolves the matching named DataSourceOptions.

DbRetryInterval

How long to wait before retrying after a database failure.

public TimeSpan DbRetryInterval { get; set; }

Property Value

TimeSpan

DoubleCheckLockMisfireHandler

Whether the misfire handler double-checks the lock before doing work.

public bool DoubleCheckLockMisfireHandler { get; set; }

Property Value

bool

IsTransient

An extra answer to "is this failure worth retrying", for a driver that reports a retryable condition Quartz does not recognise.

public Func<Exception, bool>? IsTransient { get; set; }

Property Value

Func<Exception, bool>

Remarks

Consulted first, and only additive: returning false — which is also what leaving this unset means — falls through to the built-in classification, so a predicate cannot make Quartz stop retrying something it already retries. That is deliberate. The built-in list is IsTransient, a SQLSTATE in class 40, SQL Server's transient error numbers, SQLite's busy and locked codes and TimeoutException, over the whole chain of inner exceptions; a driver that misreports one of those is a bug to fix in TransientErrorDetector rather than to work around here.

The exception handed over is the store's own, so the driver's exception is usually its InnerExceptionGetBaseException() is the short way to the one your driver threw.

It is called on the failure path of a store operation, while a lock may be held, so it must be quick and must not throw: a predicate that throws would replace the database failure the store was about to report with one from the classification of it.

LockOnInsert

Whether a lock is taken when inserting new job or trigger rows.

public bool LockOnInsert { get; set; }

Property Value

bool

MaxMisfiresToHandleAtATime

The maximum number of misfired triggers handled in a single pass.

public int MaxMisfiresToHandleAtATime { get; set; }

Property Value

int

MaxTransientRetries

The number of times a transient database failure is retried.

public int MaxTransientRetries { get; set; }

Property Value

int

MisfireHandlerFrequency

How often the misfire handler runs. Defaults to MisfireThreshold when unset.

public TimeSpan? MisfireHandlerFrequency { get; set; }

Property Value

TimeSpan?

MisfireThreshold

How far past its scheduled fire time a trigger may be before it is considered misfired.

public TimeSpan MisfireThreshold { get; set; }

Property Value

TimeSpan

OpenConnection

Whether the ambient-transaction store opens the connections it creates before handing them to an operation. Defaults to false, leaving the opening to the externally managed transaction.

public bool OpenConnection { get; set; }

Property Value

bool

Remarks

Read only by that store, which is the one UseAmbientTransactions() selects — or quartz.jobStore.type = Quartz.Impl.AdoJobStore.ExternalTransactionJobStore, Quartz. It says nothing on the default local-transaction store.

RetryableActionErrorLogThreshold

How many consecutive failures of a retryable action occur before they are logged as errors.

public int RetryableActionErrorLogThreshold { get; set; }

Property Value

int

SchemaProvisioning

What the store does about its schema at startup: nothing, verify it, or create what is missing and then verify it.

public SchemaProvisioning SchemaProvisioning { get; set; }

Property Value

SchemaProvisioning

Remarks

Defaults to Validate, which is what PerformSchemaValidation = true meant. None is the old false.

SelectWithLockSql

Overrides the SQL statement used to acquire the row lock. Defaulted for SQL Server to its WITH (UPDLOCK,ROWLOCK) form.

public string? SelectWithLockSql { get; set; }

Property Value

string

Remarks

Read only when the job store builds a database-locking handler for itself, which is what it does when UseDbLocks is on — through clustering, enlisted transactions, or the setting itself — and no lock handler was supplied. A handler chosen with UseLockHandler takes its statement through its own constructor, and the store logs a warning at startup if this is set as well, since the value would silently do nothing.

The statement must select the row in {0}LOCKS matching the @schedulerName and @lockName parameters, taking whatever lock the database needs to serialize the callers; {0} is the table prefix.

StoreJobDataAsStrings

When true, job data maps are persisted as name/value string pairs rather than serialized objects, which keeps stored data readable and version tolerant.

public bool StoreJobDataAsStrings { get; set; }

Property Value

bool

Remarks

This was UseProperties, which read as a verb and collided with QuartzSchedulerBuilder.UseProperties and AddQuartz(properties) — an unrelated thing about flat quartz.* configuration keys. The flat key that sets it is still quartz.jobStore.useProperties.

TablePrefix

The prefix applied to every Quartz table name. Defaults to DefaultTablePrefix.

public string TablePrefix { get; set; }

Property Value

string

TransactionIsolationLevel

The isolation level the job store begins its own transactions at. Left unset, they are ReadCommitted.

public IsolationLevel? TransactionIsolationLevel { get; set; }

Property Value

IsolationLevel?

Remarks

This replaced a TxIsolationLevelSerializable flag, which could say only "serializable" or "the default" and so could not express Snapshot, RepeatableRead or a deliberate ReadUncommitted. null means Quartz's default rather than the provider's, because those differ — MySQL's is repeatable read — and inheriting the provider's would silently change how the store behaves depending on which database it is talking to.

SQLite is the exception: the store forces serializable there whatever this says, because concurrent SQLite transactions at a lower level fail with "database is locked".

This applies only to connections the job store opens itself. An operation running on a connection the application enlisted uses whatever isolation level that transaction was begun at.

TransientRetryInterval

How long to wait between transient database failure retries.

public TimeSpan TransientRetryInterval { get; set; }

Property Value

TimeSpan

UseBackgroundThreads

Whether the misfire handler and cluster manager run on background threads, which do not keep the process alive on their own.

public bool UseBackgroundThreads { get; set; }

Property Value

bool

Remarks

These two are the only real threads Quartz creates — the scheduling loop is a Task — so this is the whole of the "do Quartz's threads hold my console application open" question. UseBackgroundThreads rather than MakeThreadsDaemons: "daemon" is the Java word for what .NET calls IsBackground.

UseDbLocks

Whether database row locks are used for synchronization. Required for clustering.

public bool UseDbLocks { get; set; }

Property Value

bool