Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/masastack/MASA.Framework/llms.txt

Use this file to discover all available pages before exploring further.

MASA Framework’s Background Jobs building block lets you offload work from the request thread — send emails, generate reports, or run periodic maintenance tasks — with a clean, provider-agnostic API. Switch between an in-memory provider for development and Hangfire for production by changing a single registration line.

Installation

dotnet add package Masa.Contrib.Extensions.BackgroundJobs          # core abstractions
dotnet add package Masa.Contrib.Extensions.BackgroundJobs.Hangfire  # production provider
dotnet add package Masa.Contrib.Extensions.BackgroundJobs.Memory    # dev/test provider

Core Interfaces and Classes

IBackgroundJobManager

The primary entry point for enqueuing and scheduling work:
MethodDescription
EnqueueAsync<TArgs>(TArgs args)Enqueue a fire-and-forget job to run as soon as possible
EnqueueAsync<TArgs>(TArgs args, TimeSpan delay)Enqueue a job to run after the specified delay
AddOrUpdateScheduleAsync(IBackgroundScheduleJob)Register or update a recurring (cron) job

BackgroundJobBase<TArgs>

The recommended base class for implementing jobs. Override ExecutingAsync with your business logic; the framework calls PreExecuteAsync and PostExecuteAsync as lifecycle hooks:
MemberModifierDescription
ExecutingAsync(TArgs args)abstractYour job logic — always override this
PreExecuteAsync(TArgs args)virtualRuns before execution; logs job start by default
PostExecuteAsync(TArgs args)virtualRuns after execution; logs job completion by default
ExecuteAsync(TArgs args)sealedOrchestrates Pre → Executing → Post

Supporting Types

TypeDescription
IBackgroundJob<TArgs>Interface alternative to BackgroundJobBase<TArgs>
IBackgroundScheduleJobContract for recurring jobs; implement via BackgroundScheduleJobBase
BackgroundJobNameAttributeOverride the default job name derived from the class name
JobContextContextual metadata available during job execution
IBackgroundJobProcessorImplement to insert custom processing pipeline steps

Registration

Hangfire (Production)

builder.Services.AddBackgroundJobs(jobs =>
    jobs.UseHangfire(config =>
        config.UseSqlServerStorage(connectionString)));

In-Memory (Development / Testing)

builder.Services.AddBackgroundJobs(jobs => jobs.UseInMemory());
The in-memory provider executes jobs synchronously within the same process and does not survive application restarts. Use it only for local development and unit tests.

Defining a Job

Separate the job arguments (a plain record or class) from the job implementation. This keeps args serializable and your job unit-testable in isolation:
// Job arguments — must be serializable
public record SendEmailArgs
{
    public string To { get; init; } = string.Empty;
    public string Subject { get; init; } = string.Empty;
    public string Body { get; init; } = string.Empty;
}

// Job implementation
[BackgroundJobName("SendEmail")]
public class SendEmailJob : BackgroundJobBase<SendEmailArgs>
{
    private readonly IEmailService _email;

    public SendEmailJob(IEmailService email) => _email = email;

    protected override async Task ExecutingAsync(SendEmailArgs args)
        => await _email.SendAsync(args.To, args.Subject, args.Body);
}
Decorate your job class with [BackgroundJobName] to assign a stable name. Without it the framework uses the fully qualified type name, which can break job discovery after refactoring.

Enqueuing Jobs

Inject IBackgroundJobManager wherever you need to dispatch work:
public class OrderService
{
    private readonly IBackgroundJobManager _jobs;

    public OrderService(IBackgroundJobManager jobs) => _jobs = jobs;

    public async Task PlaceOrderAsync(Order order)
    {
        // ... persist order ...

        // Fire-and-forget: send confirmation email immediately
        await _jobs.EnqueueAsync(new SendEmailArgs
        {
            To      = order.CustomerEmail,
            Subject = "Order confirmed",
            Body    = $"Your order #{order.Id} is confirmed."
        });

        // Delayed: send a follow-up reminder after 5 minutes
        await _jobs.EnqueueAsync(
            new SendEmailArgs
            {
                To      = order.CustomerEmail,
                Subject = "How's your order?",
                Body    = "Your order is on its way."
            },
            TimeSpan.FromMinutes(5));
    }
}

Recurring Jobs

Extend BackgroundScheduleJobBase and register a cron expression to run jobs on a schedule:
public class DailyReportJob : BackgroundScheduleJobBase
{
    // Cron expression: every day at 08:00 UTC
    public override string CronExpression => "0 8 * * *";

    private readonly IReportService _reports;

    public DailyReportJob(IReportService reports) => _reports = reports;

    protected override async Task ExecutingAsync()
        => await _reports.GenerateDailySummaryAsync(DateTime.UtcNow.Date);
}

// Register at startup
await backgroundJobManager.AddOrUpdateScheduleAsync(new DailyReportJob(reportService));

Lifecycle Hooks

Override PreExecuteAsync or PostExecuteAsync to add cross-cutting concerns such as distributed tracing, metrics, or audit logging without polluting ExecutingAsync:
public class AuditedJob : BackgroundJobBase<MyArgs>
{
    private readonly IAuditLog _audit;

    public AuditedJob(IAuditLog audit) => _audit = audit;

    protected override async Task PreExecuteAsync(MyArgs args)
    {
        await _audit.RecordStartAsync(nameof(AuditedJob));
        await base.PreExecuteAsync(args); // retains default logging
    }

    protected override async Task ExecutingAsync(MyArgs args)
    {
        // business logic
    }

    protected override async Task PostExecuteAsync(MyArgs args)
    {
        await _audit.RecordCompleteAsync(nameof(AuditedJob));
        await base.PostExecuteAsync(args);
    }
}

Provider Comparison

FeatureMemoryHangfire
Persistence across restarts
Dashboard UI
Delayed jobs
Recurring (cron) jobs
Distributed workers
Recommended environmentDev / TestProduction

Build docs developers (and LLMs) love