Skip to content

Handler Priority

A. Shafie edited this page Sep 26, 2025 · 1 revision

Handler Priority

LiteBus provides a mechanism to control the execution order of handlers using the [HandlerPriority] attribute. This is essential for creating deterministic workflows where certain operations must happen before others.

What is Handler Priority?

Handler Priority defines the sequence in which handlers of the same type (e.g., pre-handlers, post-handlers, or event handlers) are executed.

  • Lower numbers have higher priority (i.e., they execute first).
  • The default priority for any handler without the attribute is 0.
  • Handlers with the same priority value are not guaranteed to execute in a specific order relative to each other (unless configured for sequential execution in the Event Module).

This feature replaces the [HandlerOrder] attribute from versions prior to v4.0.

How to Use

Apply the [HandlerPriority] attribute to any handler class.

using LiteBus.Messaging.Abstractions;

[HandlerPriority(1)]
public class MyFirstHandler : ICommandPreHandler<MyCommand>
{
    // This will execute first...
}

[HandlerPriority(10)]
public class MySecondHandler : ICommandPreHandler<MyCommand>
{
    // This will execute after MyFirstHandler...
}

public class MyDefaultPriorityHandler : ICommandPreHandler<MyCommand>
{
    // This has a default priority of 0 and will execute before MyFirstHandler.
}

Use Case: Pre-Handler Ordering

Priority is commonly used to ensure validation runs before enrichment in a pre-handler chain.

// Priority 1: Validation runs first.
[HandlerPriority(1)]
public class ValidationPreHandler : ICommandPreHandler<CreateUserCommand>
{
    public Task PreHandleAsync(CreateUserCommand command, CancellationToken cancellationToken)
    {
        if (string.IsNullOrWhiteSpace(command.Email))
        {
            throw new ValidationException("Email is required.");
        }
        return Task.CompletedTask;
    }
}

// Priority 2: Enrichment runs after successful validation.
[HandlerPriority(2)]
public class EnrichmentPreHandler : ICommandPreHandler<CreateUserCommand>
{
    public Task PreHandleAsync(CreateUserCommand command, CancellationToken cancellationToken)
    {
        // Add a correlation ID to the context for other handlers to use.
        AmbientExecutionContext.Current.Items["CorrelationId"] = Guid.NewGuid();
        return Task.CompletedTask;
    }
}

Use Case: Event Handler Priority Groups

For events, handlers with the same priority value form a priority group. The EventMediationSettings control how these groups execute relative to each other.

  • By default, priority groups execute sequentially (Group 1 finishes before Group 2 starts).
  • This allows you to create phases of event processing.
// Priority 1: Initial data persistence.
[HandlerPriority(1)]
public class SaveToReadModelHandler : IEventHandler<OrderPlacedEvent> { /* ... */ }

// Priority 2: Notifications can only happen after data is saved.
[HandlerPriority(2)]
public class SendEmailToCustomerHandler : IEventHandler<OrderPlacedEvent> { /* ... */ }

[HandlerPriority(2)]
public class NotifyShippingDepartmentHandler : IEventHandler<OrderPlacedEvent> { /* ... */ }

// Priority 3: Analytics runs last.
[HandlerPriority(3)]
public class UpdateAnalyticsDashboardHandler : IEventHandler<OrderPlacedEvent> { /* ... */ }

In the example above, SaveToReadModelHandler will complete before the two notification handlers begin. The two notification handlers (both priority 2) form a group and will execute based on the HandlersWithinSamePriorityConcurrencyMode setting.

For more details, see the Event Module documentation.

Best Practices

  1. Use for Determinism: Only apply priority when a specific execution order is required for correctness (e.g., validation before action).
  2. Keep Gaps: Leave gaps between priority numbers (e.g., 10, 20, 30) to make it easier to insert new handlers in the future without re-numbering.
  3. Use Constants: Define priority levels as constants in a shared class to improve readability and avoid magic numbers.
public static class HandlerPriorities
{
    public const int Validation = 10;
    public const int Enrichment = 20;
    public const int Auditing = 100;
}
Clone this wiki locally