Skip to main content
Version: Next

10. Scheduler

10.1 Responsibilities

IBackgroundJobScheduler is intended as the single frozen entry point for all job submission — enqueue, delayed schedule, and recurring registration — replacing direct static calls to Hangfire.BackgroundJob/ Hangfire.RecurringJob. Its implementation, BackgroundJobScheduler, does nothing but forward every call to IHangfireBackgroundJobAdapter — it holds zero logic and zero Hangfire type references of its own.

10.2 Scheduling abstraction

public interface IBackgroundJobScheduler
{
Task EnqueueAsync<TJob>(Expression<Func<TJob, Task>> methodCall, BackgroundJobScheduleRequest? request = null);
Task ScheduleAsync<TJob>(Expression<Func<TJob, Task>> methodCall, TimeSpan delay, BackgroundJobScheduleRequest? request = null);
Task AddOrUpdateRecurringAsync<TJob>(string recurringJobId, Expression<Func<TJob, Task>> methodCall, string cronExpression, BackgroundJobScheduleRequest? request = null);
Task RemoveRecurringAsync(string recurringJobId);
Task TriggerRecurringAsync(string recurringJobId);
}

BackgroundJobScheduleRequest (queue, priority, tenant info, user ID, correlation ID, retry policy) is accepted on every method — but confirmed not currently forwarded to the underlying adapter call; it is silently unused today. This is a known limitation, not a documentation error.

10.3 Host interaction

IHangfireBackgroundJobAdapter (implemented by HangfireBackgroundJobAdapter, the only class in the whole framework permitted to reference Hangfire.* types) wraps:

  • EnqueueAsyncIBackgroundJobClient.Enqueue(...)
  • ScheduleAsyncIBackgroundJobClient.Schedule(..., delay)
  • AddOrUpdateRecurringAsyncIRecurringJobManager.AddOrUpdate(recurringJobId, methodCall, cron)
  • RemoveRecurringAsyncIRecurringJobManager.RemoveIfExists(...)
  • TriggerRecurringAsyncIRecurringJobManager.Trigger(...)

10.4 Recurring jobs vs. fire-and-forget — an important caveat about current production usage

None of the six migrated production jobs actually call IBackgroundJobScheduler today. Their recurring registration still goes through raw, imperative Hangfire.RecurringJob.AddOrUpdate<TPipelineJob>(...) calls directly in the ERP host's ApplicationBuilderExtensions.cs — the same pattern used before the framework existed, just now pointed at a new *PipelineJob bridge class instead of the old worker class directly. IBackgroundJobScheduler/IHangfireBackgroundJobAdapter are registered in DI and fully functional — only test code currently exercises them.

This means, precisely stated: "the Scheduler" governs nothing in production today. It is a real, working, tested abstraction, correctly designed to eventually be the single registration path — but adopting it for the six already-migrated jobs would itself be a new, separately-approved change, not something this documentation should imply has already happened.

10.5 Fire-and-forget

Supported structurally (EnqueueAsync) but not exercised by any currently-migrated production job. The legacy Product Import fire-and-forget flow predates this framework entirely and still runs on the old, unmigrated Hangfire filter-chain path — see §14.5.