IRecurringJob Interface
A no-payload job that runs on a cron schedule. Use this for periodic maintenance tasks like cache cleanup, report generation, or health checks.
Namespace: Zeridion.Flare · Assembly: Zeridion.Flare.dll
public interface IRecurringJob
{
Task ExecuteAsync(JobContext context);
}
ExecuteAsync
Task ExecuteAsync(JobContext context);
| Parameter | Type | Description |
|---|---|---|
context | JobContext | Execution context with job metadata, cancellation, and logging. |
The contract is the same as IJob<T>.ExecuteAsync — completion means success, exceptions mean failure, and the CancellationToken on the context should be passed to all async operations.
The key difference from IJob<T> is that recurring jobs have no payload. All configuration comes from the class itself and its attributes.
Cron schedule
Every IRecurringJob must have a [JobConfig] attribute with a CronSchedule property. The schedule uses standard 5-field cron format (parsed by the Cronos library):
┌───────────── minute (0–59)
│ ┌───────────── hour (0–23)
│ │ ┌───────────── day of month (1–31)
│ │ │ ┌───────────── month (1–12)
│ │ │ │ ┌───────────── day of week (0–6, Sun=0)
│ │ │ │ │
* * * * *
Common patterns:
| Expression | Meaning |
|---|---|
* * * * * | Every minute |
*/15 * * * * | Every 15 minutes |
0 * * * * | Every hour, on the hour |
0 3 * * * | Daily at 3:00 AM UTC |
0 0 * * 1 | Every Monday at midnight UTC |
0 0 1 * * | First day of every month at midnight |
Auto-registration
When the worker starts, the SDK scans assemblies for IRecurringJob implementations and sends their schedules to the Zeridion Flare API as part of POST /v1/workers/register (in the recurring_schedules array). The schedule ID is derived from the fully-qualified type name.
You do not need to call any registration method manually — AddZeridionFlare handles discovery, and the FlareWorkerService sends the registrations on startup.
Missed run handling
If the CronScheduler evaluates a recurring job and finds that one or more scheduled runs were missed (for example, the scheduler was offline), it creates a single catch-up job for the most recent missed run. It does not backfill every missed interval.
Dependency injection
Recurring job classes are registered in the DI container as their concrete type (transient). Constructor injection works normally:
[JobConfig(CronSchedule = "0 3 * * *", TimeoutSeconds = 300)]
public class CleanupExpiredSessions : IRecurringJob
{
private readonly ISessionStore _sessions;
public CleanupExpiredSessions(ISessionStore sessions) => _sessions = sessions;
public async Task ExecuteAsync(JobContext ctx)
{
var removed = await _sessions.RemoveExpiredAsync(ctx.CancellationToken);
ctx.Logger.LogInformation("Removed {Count} expired sessions", removed);
}
}
Usage example
A recurring job that generates a daily summary report:
[JobConfig(CronSchedule = "0 6 * * *", Queue = "reports", MaxAttempts = 3)]
public class DailySummaryReport : IRecurringJob
{
private readonly IReportService _reports;
private readonly IEmailService _email;
public DailySummaryReport(IReportService reports, IEmailService email)
{
_reports = reports;
_email = email;
}
public async Task ExecuteAsync(JobContext ctx)
{
ctx.Logger.LogInformation("Generating daily summary for {Date}",
DateTimeOffset.UtcNow.Date);
var report = await _reports.GenerateDailySummaryAsync(ctx.CancellationToken);
await _email.SendReportAsync("team@example.com", report, ctx.CancellationToken);
}
}
See also
- IJob<T> — payload-based jobs for event-driven work
- JobContext — the context object passed to
ExecuteAsync - [JobConfig] Attribute — where
CronScheduleis set - Recurring jobs guide — managing recurring jobs via the API and dashboard