LogoLogo
  • README
  • VERSION 9
    • Version Begins
  • Overview
    • Show me the code!
    • Basic Concepts
    • Why Brighter?
  • Brighter Configuration
    • Basic Configuration
    • How Configuring the Command Processor Works
    • How Configuring a Dispatcher for an External Bus Works
    • RabbitMQ Configuration
    • AWS SNS Configuration
    • Kafka Configuration
    • Azure Service Bus Configuration
    • Azure Archive Provider Configuration
  • Darker Configuration
    • Basic Configuration
  • Brighter Request Handlers and Middleware Pipelines
    • Building an Async Pipeline of Request Handlers
    • Basic Configuration
    • How to Implement an Async Request Handler
    • Requests, Commands and an Events
    • Dispatching Requests
    • Dispatching An Async Request
    • Returning results from a Handler
    • Using an External Bus
    • Message Mappers
    • Routing
    • Building a Pipeline of Request Handlers
    • Passing information between Handlers in the Pipeline
    • Failure and Dead Letter Queues
    • Supporting Retry and Circuit Breaker
    • Failure and Fallback
    • Feature Switches
  • Guaranteed At Least Once
    • Outbox Support
    • Inbox Support
    • EFCore Outbox
    • Dapper Outbox
    • Dynamo Outbox
    • MSSQL Inbox
    • MySQL Inbox
    • Postgres Inbox
    • Sqlite Inbox
    • Dynamo Inbox
  • Darker Query Handlers and Middleware Pipelines
    • How to Implement a Query Handler
  • Health Checks and Observability
    • Logging
    • Monitoring
    • Health Checks
    • Telemetry
  • Command, Processors and Dispatchers
    • Command, Processor and Dispatcher Patterns
  • Under the Hood
    • How The Command Processor Works
    • How Service Activator Works
  • Event Driven Architectures
    • Microservices
    • Event Driven Collaboration
    • Event Carried State Transfer
    • Outbox Pattern
  • Task Queues
    • Using a Task Queue
  • FAQ
    • FAQ
  • END OF VERSION
    • Version Ends
  • VERSION 10
    • Version Begins
  • Overview
    • Show me the code!
    • Basic Concepts
    • Why Brighter?
  • Brighter Configuration
    • Basic Configuration
    • How Configuring the Command Processor Works
    • How Configuring a Dispatcher for an External Bus Works
    • RabbitMQ Configuration
    • AWS SNS Configuration
    • Kafka Configuration
    • Azure Service Bus Configuration
    • Azure Archive Provider Configuration
  • Darker Configuration
    • Basic Configuration
  • Brighter Request Handlers and Middleware Pipelines
    • Building an Async Pipeline of Request Handlers
    • Basic Configuration
    • How to Implement an Async Request Handler
    • Requests, Commands and an Events
    • Dispatching Requests
    • Dispatching An Async Request
    • Returning results from a Handler
    • Using an External Bus
    • Message Mappers
    • Routing
    • Building a Pipeline of Request Handlers
    • Passing information between Handlers in the Pipeline
    • Failure and Dead Letter Queues
    • Supporting Retry and Circuit Breaker
    • Failure and Fallback
    • Feature Switches
  • Guaranteed At Least Once
    • Outbox Support
    • Inbox Support
    • EFCore Outbox
    • Dapper Outbox
    • Dynamo Outbox
    • MSSQL Inbox
    • MySQL Inbox
    • Postgres Inbox
    • Sqlite Inbox
    • Dynamo Inbox
  • Darker Query Handlers and Middleware Pipelines
    • How to Implement a Query Handler
  • Health Checks and Observability
    • Logging
    • Monitoring
    • Health Checks
    • Telemetry
  • Command, Processors and Dispatchers
    • Command, Processor and Dispatcher Patterns
  • Under the Hood
    • How The Command Processor Works
    • How Service Activator Works
  • Event Driven Architectures
    • Microservices
    • Event Driven Collaboration
    • Event Carried State Transfer
    • Outbox Pattern
  • Task Queues
    • Using a Task Queue
  • FAQ
    • FAQ
  • END OF VERSION
    • Version Ends
Powered by GitBook
On this page
  • CommandProcessor Configuration Dependencies
  • Subscriber Registry
  • Handler Factory
  • Policy Registry
  • Request Context Factory
  • Command Processor Builder

Was this helpful?

Edit on GitHub
  1. Brighter Configuration

How Configuring the Command Processor Works

PreviousBasic ConfigurationNextHow Configuring a Dispatcher for an External Bus Works

Last updated 2 years ago

Was this helpful?

Brighter does not have a dependency on an Inversion Of Control (IoC) framework. This gives you freedom to choose the DI libraries you want for your project.

We follow an approach outlined by Mark Seeman in his blog on a and .

This means that we can support any approach to DI that you choose, provided you implement a range of interfaces that we require to create instances of your classes at runtime.

For .NET Core's DI framework we provide the implementation of these interfaces. If you are using that approach, just follow the outline in . This chapter is 'interest only' at that point, and you don't need to read it. It may be helpful for debugging.

If you choose another DI framework, this document explains what you need to do to support that DI framework.

CommandProcessor Configuration Dependencies

  • You need to provide a Subscriber Registry with all of the Commands or Events you wish to handle, mapped to their Request Handlers.

  • You need to provide a Handler Factory to create your Handlers

  • You need to provide a Policy Registry if you intend to use to support Retry and Circuit-Breaker.

  • You need to provide a Request Context Factory

Subscriber Registry

The Command Dispatcher needs to be able to map Commands or Events to a Request Handlers.

For a Command we expect one and only one Request Handlers for an event we expect many.

YOu can use our SubcriberRegistry regardless of your DI framework.

Register your handlers with your Subscriber Registry

var registry = new SubscriberRegistry();
registry.Register<GreetingCommand, GreetingCommandHandler>();

We also support an initializer syntax

var registry = new SubscriberRegistry()
{
    {typeof(GreetingCommand), typeof(GreetingCommandHandler)}
}

Handler Factory

We don't know how to construct your handler so we call a factory, that you provide, to build your handler (and its entire dependency chain).

Instead, we take a dependency on an interface for a handler factory, and you implement that. Within the handler factory you need to construct instances of your types in response to our request to create one.

For this you need to implement the interface: IAmAHandlerFactory.

Brighter manages the lifetimes of handlers, as we consider the request pipeline to be a scope, and we will call your factory again informing that we have terminated the pipeline and finished processing the request. You should take any required action to clear up the handler and its dependencies in response to that call.

You can implement the Handler Factory using an IoC container. This is what Brighter does with .NET Core

internal class HandlerFactory : IAmAHandlerFactory
{
    private readonly TinyIoCContainer _container;

    public HandlerFactory(TinyIoCContainer container)
    {
        _container = container;
    }

    public IHandleRequests Create(Type handlerType)
    {
        return (IHandleRequests)_container.GetInstance(handlerType);
    }

    public void Release(IHandleRequests handler)
    {
        _container.Release(handler);
    }
}

Policy Registry

This is just the Polly PolicyRegistry.

Registration requires a string as a key, that you will use in your [UsePolicy] attribute to choose the policy.

The two keys: CommandProcessor.RETRYPOLICY and CommandProcessor.CIRCUITBREAKER are used within Brighter to control our response to broker issues. You can override them if you wish to change our behavior from the default.

You can also use them for a generic retry policy, though we recommend building retry policies that handle the kind of exceptions that will be thrown from your handlers.

In this example, we set up a policy. To make it easy to reference the string, instead of adding it everywhere, we use a global readonly reference, not shown here.

var retryPolicy = 
	Policy.Handle<Exception>().WaitAndRetry(
		new[] { 
			TimeSpan.FromMilliseconds(50), 
			TimeSpan.FromMilliseconds(100), 
			TimeSpan.FromMilliseconds(150) });

var circuitBreakerPolicy = Policy.Handle<Exception>().CircuitBreaker(
		1, TimeSpan.FromMilliseconds(500));

var policyRegistry = new PolicyRegistry() { 
		{ Globals.MYRETRYPOLICY, retryPolicy }, 
		{ Globals.MYCIRCUITBREAKER, circuitBreakerPolicy } 
	};

When you attribute your code, you then use the key to attach a specific policy:

[RequestLogging(step: 1, timing: HandlerTiming.Before)]
[UsePolicy(Globals.MYRETRYPOLICY, step: 2)]
public override TaskReminderCommand Handle(TaskReminderCommand command)
{
    _mailGateway.Send(new TaskReminder(
        taskName: new TaskName(command.TaskName),
        dueDate: command.DueDate,
        reminderTo: new EmailAddress(command.Recipient),
        copyReminderTo: new EmailAddress(command.CopyTo)
    ));

    return base.Handle(command);
}

If you need multiple policies then you can pass them as an array. We evaluate them left to right.

[RequestLogging(step: 1, timing: HandlerTiming.Before)]
[UsePolicy(new [] {Globals.MYRETRYPOLICY, Globals.MYCIRCUITBREAKER}, step: 2)]
public override TaskReminderCommand Handle(TaskReminderCommand command)
{
    _mailGateway.Send(new TaskReminder(
        taskName: new TaskName(command.TaskName),
        dueDate: command.DueDate,
        reminderTo: new EmailAddress(command.Recipient),
        copyReminderTo: new EmailAddress(command.CopyTo)
    ));

    return base.Handle(command);
}

Request Context Factory

Command Processor Builder

All these individual elements can be passed to a Command Processor Builder to help build a Command Processor. This has a fluent interface to help guide you when configuring Brighter. The result looks like this:

var commandProcessor = CommandProcessorBuilder.With()
    .Handlers(new HandlerConfiguration(subscriberRegistry, handlerFactory))
    .Policies(policyRegistry)
    .NoExternalBus()
    .RequestContextFactory(new InMemoryRequestContextFactory())
    .Build();

For example using :

If you intend to use a Policy to support then you will need to register the Policies in the Policy Registry.

You need to provide a factory to give us instances of a . If you have no implementation to use, just use the default InMemoryRequestContextFactory. Typically you would replace ours if you wanted to support initializing the context outside of our pipeline, for tracing for example.

DI Friendly Framework
Message Dispatching without Service Location
Basic Configuration
Polly
TinyIoC Container
Polly
Retry and Circuit-Breaker
Context