Skip to content

API reference

Application-facing Immediate.Jobs attributes, schedulers, options, monitoring, providers and testing contracts.

3 min read

This reference groups the supported application surface. Generated scheduler methods are shown on their public base contracts even though application code normally uses YourJob.Scheduler.

Declaration attributes and enums

sealed class JobAttribute : Attribute
{
	string? Name { get; init; }
	string? Cron { get; init; }
	string? TimeZone { get; init; }
	int MaxAttempts { get; init; }                 // 3
	string? Timeout { get; init; }
	int MaxConcurrency { get; init; }              // 0 = unbounded
	OverlapPolicy OverlapPolicy { get; init; }     // Skip
	BackoffStrategy Backoff { get; init; }         // ExponentialJitter
	string BackoffBase { get; init; }              // "00:00:05"
}

enum OverlapPolicy { Skip, Queue, Concurrent }
enum BackoffStrategy { Fixed, Exponential, ExponentialJitter }

sealed class QueueDefinitionAttribute : Attribute
{
	string? Name { get; init; }
	int Priority { get; init; }
	int Concurrency { get; init; }
}

sealed class UsesQueueAttribute<TQueue> : Attribute;
sealed class UsesJobContextAttribute<TExtractor> : Attribute
	where TExtractor : JobContextExtractor;

Requests, handles and context

interface IJobRequest { JobDetails? JobDetails { get; set; } }
record struct EmptyJobRequest : IJobRequest;

sealed record JobDetails(
	string JobId, string JobName, string QueueName, int Attempt,
	DateTimeOffset CreatedAt, DateTimeOffset ScheduledAt, string? BatchId = null
);

readonly struct JobHandle
{
	JobHandle(string id);
	string Id { get; }
}

sealed record BatchHandle
{
	BatchHandle(string id);
	string Id { get; }
}

public abstract class JobContextExtractor
{
	public abstract string Key { get; }
}

public abstract class JobContextExtractor<TContext> : JobContextExtractor
{
	public abstract TContext? Capture();
	public abstract void Restore(TContext context);
}

IIdGenerator.CreateId(IdKind kind) creates Job and Batch IDs. The default returns a GUID in the N format. ImmediateJobsBuilder.UseIdGenerator<TGenerator>() replaces it with a singleton, thread-safe generator; see Custom identifiers for a Snowflake example.

Typed scheduling

interface IJobScheduler<TPayload>
{
	ValueTask<JobHandle> EnqueueAsync(TPayload payload, CancellationToken token = default);
	ValueTask<JobHandle> EnqueueAsync(TPayload payload, string? groupId, CancellationToken token);
	ValueTask<JobHandle> ScheduleAsync(TPayload payload, TimeSpan delay, CancellationToken token = default);
	ValueTask<JobHandle> ScheduleAsync(TPayload payload, TimeSpan delay, string? groupId, CancellationToken token);
	ValueTask<JobHandle> ScheduleAtAsync(TPayload payload, DateTimeOffset runAt, CancellationToken token = default);
	ValueTask<JobHandle> ScheduleAtAsync(TPayload payload, DateTimeOffset runAt, string? groupId, CancellationToken token);
}

Every generated JobScheduler<TPayload> additionally exposes:

JobHandle AddToBatch(JobBatch batch, TPayload payload, TimeSpan? delay = null);
JobHandle AddToBatchInGroup(
	JobBatch batch, TPayload payload, string? groupId, TimeSpan? delay = null);
JobHandle AddToBatchAt(JobBatch batch, TPayload payload, DateTimeOffset runAt);
JobHandle AddToBatchAt(
	JobBatch batch, TPayload payload, DateTimeOffset runAt, string? groupId);

ValueTask<JobHandle> ScheduleAfterAsync(
	JobHandle parent, TPayload payload,
	ContinuationTrigger on = ContinuationTrigger.Success,
	TimeSpan? delay = null, CancellationToken token = default);
ValueTask<JobHandle> ScheduleAfterAsync(
	ReadOnlySpan<JobHandle> parents, TPayload payload,
	ContinuationTrigger on = ContinuationTrigger.Success,
	TimeSpan? delay = null, CancellationToken token = default);
ValueTask<JobHandle> ScheduleAfterAsync(
	BatchHandle parent, TPayload payload,
	ContinuationTrigger on = ContinuationTrigger.Success,
	TimeSpan? delay = null, CancellationToken token = default);

JobHandle ScheduleAfter(
	JobDetails current, TPayload payload,
	ContinuationOptions options = ContinuationOptions.BeforeContinuations);
ValueTask<JobHandle> AddToBatchAsync(
	JobDetails current, TPayload payload,
	ContinuationOptions options = ContinuationOptions.BeforeContinuations,
	CancellationToken token = default);

ContinuationTrigger.Success waits for every parent to succeed. Failure waits for every parent to become terminal and then runs when at least one failed. Complete waits for every parent to become terminal regardless of outcome. A BatchHandle is a single parent whose state becomes Failed when any item in the completed batch failed; cancellation alone does not satisfy Failure.

ContinuationOptionsBatch membershipEffect on the current job’s existing continuations
DetachedNoneUnchanged; valid only with ScheduleAfter.
BesideContinuationsCurrent batchUnchanged; the new job forms a parallel branch.
BeforeContinuations (default)Current batchThey also wait for the new job, creating an additive dependency.

Recurring and batches

interface IRecurringJobTrigger
{
	ValueTask<JobHandle> TriggerNowAsync(CancellationToken token = default);
}

interface IRecurringJobScheduler : IRecurringJobTrigger
{
	ValueTask AddOrUpdateRecurringAsync(
		string name, string cron, string timeZone = "UTC",
		CancellationToken token = default);
	ValueTask RemoveRecurringAsync(string name, CancellationToken token = default);
}

public sealed class JobBatch : IAsyncDisposable
{
	public string Id { get; }
	public ValueTask<BatchHandle> CommitAsync(CancellationToken token = default);
}

interface IJobBatchScheduler
{
	JobBatch Begin();
	JobBatch Begin(BatchHandle after, ContinuationTrigger on = ContinuationTrigger.Success);
	ValueTask<BatchHandle> RunAsync(
		Func<JobBatch, ValueTask> body, CancellationToken token = default);
}

BatchState is Executing, Succeeded, Failed, or Cancelled.

Runtime configuration

AddXxxJobs(Action<ImmediateJobsOptions>? configure = null, params ... tags) returns ImmediateJobsBuilder.

ImmediateJobsOptions memberDefault
MaxParallelJobsMath.Clamp(Environment.ProcessorCount * 4, 8, 32)
AcquisitionBatchSize32
PollingInterval1 second
LeaseDuration30 seconds
ShutdownTimeout30 seconds
SucceededRetention / BatchSucceededRetention24 hours
FailedRetention / BatchFailedRetention7 days
PurgeInterval1 hour
StorageModeInMemory when no storage provider is selected

Fluent methods are UseInMemory(), UseStorage(factory), UseSingleServer(), UseSingleServer(factory), UseDistributed() and UseFairQueues(configure). FairQueueOptions has ConcurrencyShareThreshold = 0.10, MinInflightForNoisy = 30, and GroupRoundRobin = true. Builder extensions are UseIdGenerator<TGenerator>() and AddHealthCheck(name = "immediate-jobs", failureStatus = null, tags = null).

ImmediateJobsOptions.StorageMode starts as SingleServer, which is the default topology when a durable factory does not select another mode. During registration, however, no selected storage factory causes Jobs to call UseInMemory(); the effective no-provider mode is therefore InMemory.

Serialization and telemetry

IJobSerializer exposes generic Serialize/Deserialize pairs both with and without a generated JsonTypeInfo<T> factory. SystemTextJsonJobSerializer uses web defaults and exposes Options. Generated jobs always call the metadata-factory overload. JobTelemetry.ActivitySource and JobTelemetry.Meter are the public OpenTelemetry entry points.

Monitoring

interface IJobMonitor
{
	ValueTask<JobStatus?> GetJobAsync(string jobId, CancellationToken token = default);
}

interface IJobBatchMonitor
{
	ValueTask<BatchStatus?> GetStatusAsync(string batchId, CancellationToken token = default);
	ValueTask<IReadOnlyList<BatchMemberStatus>> QueryMembersAsync(
		string batchId, BatchMemberQuery query, CancellationToken token = default);
	ValueTask<BatchGraph?> GetGraphAsync(string batchId, CancellationToken token = default);
}

BatchMemberQuery and JobBatchQuery contain optional state, Skip, and Take = 100. JobStatus, BatchStatus, BatchMemberStatus, BatchGraph, BatchGraphNode and BatchGraphEdge are immutable monitoring records.

Dashboard

RouteGroupBuilder MapImmediateJobsDashboard(
	this IEndpointRouteBuilder endpoints,
	Action<ImmediateJobsDashboardOptions>? configure = null);
RouteGroupBuilder MapImmediateJobsDashboard(
	this IEndpointRouteBuilder endpoints, string prefix,
	Action<ImmediateJobsDashboardOptions>? configure = null);

ImmediateJobsDashboardOptions.UpdateInterval defaults to two seconds. RequireAuthorization(string policy) and AddTelemetryLink(string label, JobTelemetryLinkKind kind, Func<JobTelemetryLinkContext, Uri?> createUrl) return the same options object. Link kinds are Trace and Logs.

Provider registration

ImmediateJobsOptions UseEntityFrameworkCore<TContext>();
ModelBuilder AddImmediateJobs(string? schema = null);

ImmediateJobsOptions UseLinqToDB(DataOptions dataOptions, string? schema = null);
Task CreateImmediateJobsSchemaAsync(
	this DataOptions dataOptions, string? schema = null,
	CancellationToken token = default);

ImmediateJobsOptions UseRedis(
	string configuration, Action<RedisJobStorageOptions>? configure = null);
ImmediateJobsOptions UseRedis(
	IConnectionMultiplexer connection, Action<RedisJobStorageOptions>? configure = null);

RedisJobStorageOptions exposes Database = -1 and KeyPrefix = "immediate-jobs".

NodaTime

Extension overloads mirror ScheduleAsync(Duration), ScheduleAtAsync(Instant), grouped variants, AddToBatch(Duration?), AddToBatchAt(Instant), all three ScheduleAfterAsync(Duration?) forms, and AddOrUpdateRecurringAsync(..., DateTimeZone, ...). Serialization APIs are JsonSerializerOptions.UseNodaTime(...), IServiceCollection.AddImmediateJobsNodaTime(...) and the three NodaTimeJobSerializer constructors. See the NodaTime guide for registration and examples.

Testing

CaptureOnlyJobScheduler<T> exposes Captures, Last, Clear() and virtual scheduling methods; each ScheduledJobCapture<T> contains Id, Payload, RunAt, and GroupId. CaptureOnlyRecurringJobScheduler exposes the same capture pattern with RecurringJobCapture/RecurringJobOperation.

JobTestHarness constructors accept optional service configuration and optional fake-time start; it exposes Services, Storage, TimeProvider, and Batches. Operations are DrainAsync, both AdvanceTimeAndDrainAsync overloads, QueryJobsAsync, both GetJobAsync overloads, both AssertEnqueuedAsync<T> overloads, AssertBatchCommittedAtomicallyAsync, AssertContinuationReleasedAfterAsync, AssertCascadeCancelledAsync, and RunThroughPipelineAsync<T>.

Custom storage contracts

InterfaceAtomic responsibilities
IJobStorageInitialize; enqueue; lease/acquire/renew; persist execution telemetry; complete/fail; query/status; retry/delete/purge; heartbeat and health.
IRecurringJobStorageUpsert/remove/pause/resume schedules; identify due rows; uniquely materialize each occurrence; reconcile obsolete code-defined schedules.
IJobGraphStorageAtomically enqueue batches/edges; settle and release/cascade dependencies; add mid-run members; monitor/cancel/delete/purge graphs.
IJobStorageReplicaRestore durable records and mirror explicit acquisitions for the single-server wrapper.

StorageCapabilities flags are Queue, Recurring and Graph; call storage.GetCapabilities() to detect the optional interfaces. Low-level JobRecord, acquisition, definition and graph persistence records are provider contracts, not application scheduling APIs.