Enqueue and schedule jobs
Inject JobQueue<TRecord> wherever your application creates background work.
Enqueue a job
public sealed class RegistrationService(JobQueue<JobRecord> queue)
{
public async Task RegisterAsync(Guid userId)
{
await queue.EnqueueAsync<EmailJobs>(jobs =>
jobs.SendWelcomeEmailAsync(userId));
}
}
Job methods must return Task. Their constructor dependencies are resolved when the runner executes the job.
Track a job
EnqueueAsync returns the generated tracking ID after the provider stores the record.
var trackingId = await queue.EnqueueAsync<ReportJobs>(jobs =>
jobs.GenerateAsync(reportId));
Store this ID when your application needs to associate the job with another record or cancel it later.
Schedule a job
Pass executeAfter to prevent the job from running before a UTC timestamp:
await queue.EnqueueAsync<ReminderJobs>(
jobs => jobs.SendAsync(reminderId),
executeAfter: DateTime.UtcNow.AddHours(2));
This schedules one execution. See the recurring job example for an application-defined recurring schedule.
Scheduling and explicit trace parenting can also be supplied with EnqueueOptions:
await queue.EnqueueAsync(
new EnqueueOptions
{
ExecuteAfter = DateTime.UtcNow.AddHours(2),
ParentContext = upstreamActivityContext
},
(ReminderJobs jobs) => jobs.SendAsync(reminderId));
ParentContext is optional. By default, enqueueing uses Activity.Current; an explicit context controls the producer activity and the context propagated to the worker. The API accepts ActivityContext, not raw trace header strings. GUSTO propagates W3C trace context automatically but does not persist baggage.
Prefer EnqueueAsync for normal use: it creates the full EnqueueJob producer span, constructs the record, and stores it. Extension methods can instead call ConstructRecordFromExpression; this only constructs a record and neither creates EnqueueJob nor stores anything. Its existing overloads persist a valid ambient W3C context, while overloads accepting ActivityContext? persist that explicit valid context. An explicit null, default, or otherwise invalid context means no trace context and does not fall back to ambient.
Cancellation tokens
If a job method accepts a CancellationToken, pass default when enqueueing it:
await queue.EnqueueAsync<ReportJobs>(jobs =>
jobs.GenerateAsync(reportId, default));
The runner supplies the execution token when the job runs. It is cancelled when the host stops or the configured job timeout is reached.
Cancel a queued job
Cancellation behavior is defined by your provider. Call CancelJobAsync with the tracking ID:
await queue.StorageProvider.CancelJobAsync(
trackingId,
cancellationToken);
The provider can delete the record or update its application-specific state.
Pending jobs store the target type, method name, and serialized arguments. Keep those methods compatible while matching jobs remain in storage.
New records store arguments in a versioned GUSTO envelope. Workers continue to accept the legacy top-level argument array, so existing persisted jobs remain executable.