Table of Contents

Interface IJobExecutionContextAccessor

Namespace
Quartz
Assembly
Quartz.dll

The job execution the calling code is part of, for code that cannot be handed an IJobExecutionContext: a scoped service, a logging enricher, a repository three calls below Execute.

public interface IJobExecutionContextAccessor

Examples

public sealed class TenantConnectionFactory(IJobExecutionContextAccessor accessor)
{
    public string ConnectionString =>
        connectionStrings[accessor.Current?.Trigger.Key.Group ?? throw new InvalidOperationException(
            "there is no job running on this flow to take a tenant from")];
}

Remarks

Registered by AddQuartz as a singleton, so any container with Quartz in it has one. It answers for the firing of whichever scheduler is running in this asynchronous flow, which is why it is not one of a scheduler's own parts: a flow is inside at most one firing, whatever container owns the scheduler that started it.

When it is set. From the moment the execution context exists — before the trigger and job listeners are notified — until the job has been returned to the job factory. Outside that window it is null: on the scheduler's own threads, in application code that merely schedules something, and in a ISchedulerListener reacting to a scheduling call rather than to a firing.

It is never another firing's. The value travels with ExecutionContext, so it is a property of the logical flow rather than of the thread, and a pooled thread picking up unrelated work does not inherit it. The end of a firing additionally clears the value through every flow that captured it — so work started inside a job and left running past the end of the execution, with Task.Run or a detached continuation, reads null from that point rather than a context whose scope has been disposed and whose cancellation handle is gone. There is deliberately no setter: an ambient context anyone can assign is an ambient context that can be left pointing at a firing that is over.

What it is not. It is not available while the job is being constructed: the execution context takes the job instance, so it does not exist until the job factory has produced one. Seeding a job's dependency injection scope is still ConfigureJobScope's job, which is handed the TriggerFiredBundle before anything is resolved — populate a scoped holder object from it, or set an AsyncLocal<T>. Code that reads the tenant when it is used rather than when it is constructed can read it from here instead and needs neither.

What it exposes. The whole IJobExecutionContext, rather than a tenant-shaped projection of it. Quartz has no tenant concept and is not going to get one, so a narrower type here would be inventing exactly that — and it would have to grow a member every time somebody needed one more fact the context already carries.

Properties

Current

The firing the calling code is part of, or null when it is not part of one.

IJobExecutionContext? Current { get; }

Property Value

IJobExecutionContext