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:
EnqueueAsync→IBackgroundJobClient.Enqueue(...)ScheduleAsync→IBackgroundJobClient.Schedule(..., delay)AddOrUpdateRecurringAsync→IRecurringJobManager.AddOrUpdate(recurringJobId, methodCall, cron)RemoveRecurringAsync→IRecurringJobManager.RemoveIfExists(...)TriggerRecurringAsync→IRecurringJobManager.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.