.NET React Templates
Development

Add a background job

Use ServiceStack Background Jobs for work that is slow, retryable, scheduled, or should survive the initiating request.

Development recipes · Background processing

1. Define a small command payload

Persist business state first, then enqueue only stable identifiers:

public class ProcessWidget
{
    public string WidgetId { get; set; } = "";
}

[Worker("widgets")]
public class ProcessWidgetCommand(IDbConnectionFactory dbFactory)
    : AsyncCommand<ProcessWidget>
{
    protected override async Task RunAsync(
        ProcessWidget request, CancellationToken token)
    {
        using var db = dbFactory.Open();
        var widget = db.SingleById<Widget>(request.WidgetId)
            ?? throw new InvalidOperationException("Widget was not found.");

        if (widget.Status == WidgetStatus.Completed)
            return;

        await ProcessAsync(widget, token);
        widget.Status = WidgetStatus.Completed;
        widget.ModifiedDate = DateTime.UtcNow;
        db.Update(widget);
    }
}

Do not serialize uploads, secrets, large documents, sessions, or an open database connection into a job request.

Idempotent Background Job Recovery

2. Register and enqueue

Register the command in MyApp/Configure.BackgroundJobs.cs:

services.AddTransient<ProcessWidgetCommand>();

Enqueue after the referenced row exists:

jobs.EnqueueCommand<ProcessWidgetCommand>(
    new ProcessWidget { WidgetId = widget.Id });

Use a named [Worker] when the workload should have an independent queue/concurrency boundary.

3. Add recurring work only when needed

Register recurring commands after the application host initializes:

jobs.RecurringCommand<RepairWidgetsCommand>(Schedule.Hourly);

Recurring jobs must be safe when two ticks overlap or a prior run partially completed. Query bounded batches and checkpoint durable progress.

Reliability rules

  • Make the handler idempotent and return successfully when work is already complete.
  • Re-read authoritative state inside the job; do not trust stale enqueue-time decisions.
  • Preserve the tenant ID on every loaded/mutated resource.
  • Use provider idempotency keys for external side effects.
  • Store attempts/status/error on domain or inbox records when operators need recovery visibility.
  • Compensate quota reservations when terminal work fails.
  • Pass and honor cancellation tokens.

Use /admin-ui for general job inspection and /admin/operations for product-specific failed queues and safe retries.

Verify

Test successful execution, duplicate delivery, missing/already-complete records, transient failure and retry, terminal failure, cancellation, tenant isolation, quota compensation, and recurring overlap. Run the application long enough to exercise the real hosted worker.