Filters
Overview
Section titled “Overview”Filters are middleware for job execution. They wrap the job handler and run before and after each execution, letting you add cross-cutting behavior like logging, metrics, authorization, or error handling.
Writing a filter
Section titled “Writing a filter”Implement IJobFilter. Call next(context) to continue the pipeline, or skip it to short-circuit execution.
public class LoggingFilter : IJobFilter{ public async Task InvokeAsync(JobContext context, JobFilterDelegate next) { var sw = Stopwatch.StartNew(); Console.WriteLine($"Starting {context.JobName}");
await next(context);
Console.WriteLine($"Finished {context.JobName} in {sw.ElapsedMilliseconds}ms"); }}Registering filters
Section titled “Registering filters”Global filters
Section titled “Global filters”Global filters run on every job. Register them with UseFilter<T> in the Surefire configuration:
builder.Services.AddSurefire(options =>{ options.UseFilter<LoggingFilter>(); options.UseFilter<TenantFilter>();});Filters run in the order they’re registered. The first filter registered is the outermost layer of the pipeline.
Per-job filters
Section titled “Per-job filters”Per-job filters run only on a specific job. Add them with UseFilter<T> on the job builder:
app.AddJob("Import", async () => { /* ... */ }) .UseFilter<AuditFilter>();Per-job filters are resolved from DI if registered, or created via ActivatorUtilities if not. Their constructor parameters are injected automatically.
Pipeline order
Section titled “Pipeline order”Global filters wrap all jobs. Per-job filters wrap only their specific job. Filters execute in registration order.
Examples
Section titled “Examples”Error notification filter
Section titled “Error notification filter”public class SlackNotificationFilter(SlackClient slack) : IJobFilter{ public async Task InvokeAsync(JobContext context, JobFilterDelegate next) { try { await next(context); } catch (Exception ex) { await slack.PostAsync($"Job {context.JobName} failed: {ex.Message}"); throw; } }}Timing filter
Section titled “Timing filter”public class TimingFilter(ILogger<TimingFilter> logger) : IJobFilter{ public async Task InvokeAsync(JobContext context, JobFilterDelegate next) { var sw = Stopwatch.StartNew();
await next(context);
logger.LogInformation("Job {Name} took {Ms}ms", context.JobName, sw.ElapsedMilliseconds); }}