Scheduling Helpers

Helper classes for defining when and how scheduled jobs run: the Every and Cron factory classes for creating Schedule objects, the Schedule record itself, and ManifestOptions for per-job configuration.


Every

Static factory class for creating interval-based schedules.

public static class Every

The shortest interval is one second. A zero or negative count throws ArgumentOutOfRangeException at the call, since the manifest stores whole seconds and would otherwise store zero. A new interval schedule runs on the first poll after it is scheduled, then once per interval after each success.

MethodSignatureDescription
Secondsstatic Schedule Seconds(int seconds)Run every N seconds
Minutesstatic Schedule Minutes(int minutes)Run every N minutes
Hoursstatic Schedule Hours(int hours)Run every N hours
Daysstatic Schedule Days(int days)Run every N days

Examples

Every.Seconds(30)   // Every 30 seconds
Every.Minutes(5)    // Every 5 minutes
Every.Hours(2)      // Every 2 hours
Every.Days(1)       // Every day

Cron

Static factory class for creating cron-based schedules with readable methods. Supports both standard 5-field (minute granularity) and 6-field (second granularity) cron formats. For complex expressions, use Cron.Expression().

Every cron time is UTC. Cron.Daily(hour: 3) runs at 03:00 UTC, whatever the host's time zone.

Each method builds its schedule through Schedule.FromCron, which parses the expression, so a value out of range throws FormatException at the call that states it: Cron.Daily(hour: 25), Cron.Hourly(minute: 60), or a malformed Cron.Expression(...). So does a valid expression with no occurrence in the next ten years, such as 0 0 30 2 * (February 30th), with a message saying it never fires; a cron that fires only in leap years is accepted. A cron stored some other way that has no occurrence at all is never due.

A new cron schedule first runs at its first occurrence after it is scheduled, not on the next poll: Cron.Daily(hour: 3) scheduled at 14:00 first runs at 03:00 the next day. Scheduling records that occurrence on the manifest's NextScheduledRun, and re-stating the same cron at a restart keeps it. A cron manifest written by an earlier Trax version that has never succeeded and has no stored NextScheduledRun is due on the next poll instead; scheduling it again, which the builder does for its own manifests at every start, records its first occurrence.

public static class Cron
MethodSignatureDescription
Secondlystatic Schedule Secondly()Every second (* * * * * *)
Minutelystatic Schedule Minutely()Every minute (* * * * *)
Minutelystatic Schedule Minutely(int second)Every minute at the specified second
Hourlystatic Schedule Hourly(int minute = 0, int second = 0)Every hour at the specified minute/second
Dailystatic Schedule Daily(int hour = 0, int minute = 0, int second = 0)Every day at the specified time
Weeklystatic Schedule Weekly(DayOfWeek day, int hour = 0, int minute = 0, int second = 0)Every week on the specified day/time
Monthlystatic Schedule Monthly(int day = 1, int hour = 0, int minute = 0, int second = 0)Every month on the specified day/time
Expressionstatic Schedule Expression(string cronExpression)From a raw 5-field or 6-field cron string

When a second parameter is 0 (the default), the method produces a standard 5-field expression. When second is non-zero, it produces a 6-field expression with seconds.

Examples

// 5-field (minute granularity)
Cron.Minutely()                              // Every minute
Cron.Hourly(minute: 30)                      // Every hour at :30
Cron.Daily(hour: 3)                          // Daily at 03:00 UTC
Cron.Daily(hour: 14, minute: 30)             // Daily at 14:30 UTC
Cron.Weekly(DayOfWeek.Monday, hour: 9)       // Every Monday at 09:00 UTC
Cron.Monthly(day: 15, hour: 0)               // 15th of each month at midnight UTC
Cron.Expression("0 */6 * * *")              // Every 6 hours (custom cron)
 
// 6-field (second granularity)
Cron.Secondly()                              // Every second
Cron.Minutely(second: 30)                   // Every minute at :30 seconds
Cron.Hourly(minute: 15, second: 45)         // Every hour at 15:45
Cron.Daily(hour: 3, minute: 0, second: 30)  // Daily at 03:00:30 UTC
Cron.Expression("*/15 * * * * *")           // Every 15 seconds (custom 6-field)

Cron Expression Format

Trax supports both standard 5-field and 6-field (with seconds) cron formats. The format is auto-detected by counting fields. Expressions are evaluated in UTC.

5-field (minute granularity): minute hour day-of-month month day-of-week

FieldRangeSpecial Characters
Minute0-59* , - /
Hour0-23* , - /
Day of month1-31* , - /
Month1-12* , - /
Day of week0-6 (0 = Sunday)* , - /

6-field (second granularity): second minute hour day-of-month month day-of-week

FieldRangeSpecial Characters
Second0-59* , - /
Minute0-59* , - /
Hour0-23* , - /
Day of month1-31* , - /
Month1-12* , - /
Day of week0-6 (0 = Sunday)* , - /

Note: 7-field cron (with year) is not supported. The effective resolution of seconds-granularity cron is limited by the ManifestManagerPollingInterval (default: 5 seconds).


Schedule (Record)

An immutable record that represents a schedule definition. Created by Every, Cron, or the static factory methods.

public record Schedule

Properties

PropertyTypeDescription
TypeScheduleTypeCron or Interval
IntervalTimeSpan?The interval between executions (only for ScheduleType.Interval)
CronExpressionstring?The cron expression, 5-field or 6-field, evaluated in UTC (only for ScheduleType.Cron)

Factory Methods

MethodSignatureDescription
FromIntervalstatic Schedule FromInterval(TimeSpan interval)Creates an interval-based schedule. Throws ArgumentOutOfRangeException for an interval shorter than one second.
FromCronstatic Schedule FromCron(string expression)Creates a cron-based schedule. Parses the expression and throws FormatException when it is not a valid 5-field or 6-field cron.

ToCronExpression

public string ToCronExpression()

Converts the schedule to a cron expression (5-field or 6-field). For cron-type schedules, returns the expression as-is. For interval-type schedules, converts to the closest valid cron expression. Sub-minute intervals produce 6-field (seconds) cron; minute-or-above intervals produce 5-field cron.

Approximation: Cron cannot express all intervals. Intervals that don't divide evenly into 60 minutes or 60 seconds are approximated to the nearest valid cron divisor of 60 (1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30).

ScheduleType Enum

ValueDescription
NoneManual-only; must be triggered via API
CronRuns on a cron expression schedule
IntervalRuns at a fixed time interval
OnDemandBatch operations triggered programmatically
DependentRuns after a parent manifest completes successfully
DormantDependentA dependent that must be explicitly activated at runtime via IDormantDependentContext. Never auto-fires.
OnceFires once at ScheduledAt, then auto-disables on success. Created by ScheduleOnceAsync. See Delayed / One-Off Jobs.

MisfirePolicy Enum

Determines behavior when a scheduled run is missed.

ValueDescription
FireOnceNowFire once immediately if overdue. Default behavior.
DoNothingIf overdue beyond the misfire threshold, skip and wait for the next natural occurrence.

See Misfire Policies for detailed behavior and examples.

ExclusionType Enum

Defines the kind of exclusion window for a manifest schedule. Used inside the JSONB exclusions column.

ValueDescription
DaysOfWeekExclude specific days of the week (e.g., weekends)
DatesExclude specific dates (e.g., holidays)
DateRangeExclude a contiguous date range (start–end inclusive)
TimeWindowExclude a daily time window (supports midnight crossover)

See Exclusion Windows for usage patterns and examples.


ManifestOptions

Per-item configuration passed to the configureEach callback of the batch scheduling methods (ScheduleMany, IncludeMany, ThenIncludeMany, ScheduleManyAsync, ScheduleManyDependentAsync), which receives each source item and its ManifestOptions. A single manifest, and settings shared by a whole batch, are configured through the ScheduleOptions builder instead.

public class ManifestOptions
PropertyTypeDefaultDescription
IsEnabledbooltrueWhether the manifest is enabled. When false, ManifestManager skips it during polling, a dormant dependent is not activated, and the dispatcher holds the manifest's scheduled entries until it is re-enabled (a trigger or a dead-letter requeue still runs). Written to an existing manifest only when set, so a re-seed that leaves it unset keeps a runtime disable. See Disabling a job.
MaxRetriesintDefaultMaxRetries (3)Retries after the first run before the job is dead-lettered (the default allows four attempts; 0 dead-letters on the first failure). Each retry creates a new Metadata record. Setting a negative value throws ArgumentOutOfRangeException. Unset, a new manifest takes the scheduler's DefaultMaxRetries and an existing one keeps its stored value at a re-seed; inside configureEach it reads the batch's resolved value.
FailureWindowTimeSpan?nullHow far back this manifest's failed runs count toward its retry backoff and MaxRetries. null uses the scheduler's FailureCountWindow. Stored in whole seconds; throws ArgumentOutOfRangeException unless between one second and ten years. Written to an existing manifest only when stated, so a manifest that stops stating it keeps the window it has. Can also be set with ScheduleOptions.FailureWindow(...).
TimeoutTimeSpan?nullPer-job timeout override. null falls back to the global DefaultJobTimeout. Written to an existing manifest only when set (setting null states "use the global default"). A run that exceeds it is cancelled, and trains nested inside the run share it, and the stale in-progress reaper waits at least this long (plus its grace) before failing a run.
Priorityint0Manifest-level priority stored on the manifest record. Written to an existing manifest only when set; a new one takes 0. The dispatcher orders by ManifestGroup.Priority first, then by the entry's priority, and every entry for the manifest (scheduled, triggered or requeued) is queued at this priority. For dependent manifests, DependentPriorityBoost (default 16) is added on top at dispatch time. Can also be set with ScheduleOptions.Priority(...).
MisfirePolicyMisfirePolicy?nullPer-manifest misfire policy override. null uses the global DefaultMisfirePolicy. Only applies to Cron and Interval schedule types. See Misfire Policies.
MisfireThresholdTimeSpan?nullPer-manifest misfire threshold override. null uses the global DefaultMisfireThreshold (60 seconds).
ExclusionsList<Exclusion>[]Exclusion windows for this manifest. When any exclusion matches the current time, the manifest is skipped. Excluded periods are "intentionally skipped", not misfires. See Exclusion Windows.

Example

// Per item, through configureEach on a batch...
await scheduler.ScheduleManyAsync<ISyncTableTrain, SyncTableInput, Unit, string>(
    tables,
    table => ($"sync-{table}", new SyncTableInput { TableName = table }),
    Every.Minutes(5),
    configureEach: (table, opts) =>
    {
        opts.MaxRetries = table == "orders" ? 5 : 3;
        opts.Timeout = TimeSpan.FromMinutes(30);
        opts.Priority = 20;
    });
 
// ...or for a single manifest, through the ScheduleOptions builder
await scheduler.ScheduleAsync<IMyTrain, MyInput, Unit>(
    "my-job",
    new MyInput(),
    Every.Minutes(5),
    options => options.MaxRetries(5).Timeout(TimeSpan.FromMinutes(30)).Priority(20));