Skip to content

Queues and fairness

Define queues and combine priority, concurrency and fair-group scheduling.

2 min read

Define a marker type and assign jobs to it:

[QueueDefinition(Name = "transactional-email", Priority = 100, Concurrency = 2)]
public sealed class TransactionalEmailQueue;

[Handler, Job, UsesQueue<TransactionalEmailQueue>]
public sealed partial class SendWelcomeEmail(IEmailSender sender)
{
	// HandleAsync omitted
}

Without [UsesQueue<T>], a job uses the built-in default queue (Priority = 0, Concurrency = 0). A custom persisted name defaults to the class name with a Queue suffix converted to kebab case (TransactionalEmailQueue becomes transactional-email-queue). Set Name explicitly for production. Names must be unique, must not be default, and queue concurrency cannot be negative.

Higher Priority queues are considered first. Concurrency limits in-flight work for that queue on one scheduler node; zero is unbounded. Node-wide MaxParallelJobs and job-level MaxConcurrency still apply, so priority never bypasses capacity.

Fair groups

Enable fairness globally and put a tenant/customer key on each scheduled invocation:

builder.Services.AddMyAppJobs(options =>
{
	options.UseFairQueues(fair =>
	{
		fair.ConcurrencyShareThreshold = 0.10;
		fair.MinInflightForNoisy = 30;
		fair.GroupRoundRobin = true;
	});
});

await welcomeEmail.EnqueueAsync(
	new(userId, "v2"),
	groupId: tenantId,
	cancellationToken: cancellationToken
);

Round-robin interleaves due groups. A group becomes noisy only after it has at least MinInflightForNoisy active jobs and exceeds ConcurrencyShareThreshold of the queue’s effective capacity; quieter groups are then preferred. Ungrouped jobs remain eligible. Fairness affects acquisition order, not durable priority or a job’s retry policy.

Provider/topologyFair groups
In-memorySupported
EF Core / LinqToDBSupported
RedisNot supported; grouped acquisition is rejected
Single-server wrapperSupported when its durable replica has full graph/fair semantics

Queue and group names are persisted. Renaming either does not migrate existing work.