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; }