Skip to content

Add Task Scheduler API on top of BackgroundJobs (cron-like fluent scheduling) #159

@antosubash

Description

@antosubash

Background

BackgroundJobs already persists ScheduledAt and CronExpression columns, but there is no fluent API to register recurring jobs at module-startup time, nor a worker that wakes up and enqueues due jobs. Laravel's Kernel::schedule() is the canonical example: every cron tick the scheduler enumerates definitions and dispatches due ones.

Motivation

  • Most apps need recurring work: nightly cleanup, daily digest emails, hourly sync, etc.
  • Schema is already in place; only the dispatcher + DSL are missing
  • Eliminates per-app cron + AppHost glue

Design sketch

public interface IScheduler
{
    IScheduledJob<T> Job<T>() where T : IBackgroundJob;
}

public interface IScheduledJob<T>
{
    IScheduledJob<T> Cron(string expression);
    IScheduledJob<T> Daily();
    IScheduledJob<T> DailyAt(string time);          // "03:00"
    IScheduledJob<T> EveryMinutes(int minutes);
    IScheduledJob<T> Hourly();
    IScheduledJob<T> Weekdays();
    IScheduledJob<T> Timezone(string tz);
    IScheduledJob<T> WithoutOverlapping();          // mutex via DB
    IScheduledJob<T> OnOneServer();                 // leader election
    IScheduledJob<T> WithPayload(object payload);
}

Module registers schedules in IModule.ConfigureServices:

scheduler.Job<NightlyAuditPurge>().DailyAt("02:00").Timezone("UTC");
scheduler.Job<DigestEmail>().Cron("0 8 * * MON-FRI").WithoutOverlapping();
  • A hosted SchedulerService polls every 30s, computes due jobs from registered definitions, inserts into BackgroundJobs queue
  • Distributed safety: WithoutOverlapping writes a mutex row keyed by job-name; OnOneServer uses an instance-id leader lease (DB row with TTL)
  • Cron parsing via Cronos (already on .NET; widely used)

Acceptance criteria

  • IScheduler exposed from BackgroundJobs.Contracts
  • SchedulerService runs as IHostedService in worker process
  • Mutex (WithoutOverlapping) and leader (OnOneServer) primitives implemented and tested
  • Failure isolation: one bad definition does not stop the loop
  • xUnit tests cover cron parsing, due-time calc, mutex contention
  • Docs: how to register a scheduled job
  • CLI: sm jobs list-scheduled prints next-run-at

References

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions