Skip to content

A job registered with AddJob<T> is activated by the container, so it gets the default scheduler's parts #3388

Description

@lahma

Found by the multi-tenancy audit for alpha.2; the documentation is being corrected to describe it, this issue is about whether to change it.

A job is handed different collaborators depending on whether the container holds a registration for its type:

  • AddJob<T> registers the job type with TryAddScoped (src/Quartz/Configuration/QuartzBuilderExtensions.cs, the TryAddScoped(jobType) helper). MicrosoftDependencyInjectionJobFactory then resolves it from the fire scope, so the container activates it — and a constructor that takes ISchedulerFactory, IJobStore, IThreadPool or IOptions<QuartzSchedulerOptions> receives the default scheduler's (or fails container validation in a container with only named schedulers).
  • A job type the container does not hold is created through JobActivatorCache on the scheduler-scoped provider, and the same constructor receives its own scheduler's parts.

So registering a job — the documented, recommended thing to do — changes which scheduler's collaborators it sees. It works in every single-scheduler test and surprises in production with two tenants.

Options

  1. Refuse the ambiguity at startup. Validate registered job types' constructors: a parameter of a per-scheduler type (ISchedulerFactory, IScheduler, IJobStore, IThreadPool, IOptions<QuartzSchedulerOptions>, …) fails ValidateOnStart with a message pointing at IJobExecutionContext.Scheduler / IJobExecutionContextAccessor. Cheap, honest, and it matches the guidance the docs give anyway. Cost: a job that genuinely wants to inject its scheduler cannot, which today only half works.
  2. Make registered jobs scheduler-aware. Have the job factory build registered job types through the scheduler-scoped provider as well. This is only coherent for scoped and transient registrations — a singleton job type shared by two schedulers can hold only one set of parts — so it would need to refuse or special-case singletons, and it changes the lifetime story AddJobType<T>(ServiceLifetime) just settled.
  3. Document only. The alpha.2 docs pass says both halves on multi-tenancy.md. That is the floor, not the answer.

I lean to (1) for 4.0: it removes a trap without adding a mechanism, and (2) can still be built later if a real case for injecting a scheduler into a job appears.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    4.xCandidate for main/4.x branch

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions