# Basic Configuration

Configuration is the most labor-intensive part of using Brighter.Once you have configured Brighter, using its model of requests and handlers is straightforward

## **Using .NET Core Dependency Injection**

This section covers using .NET Core Dependency Injection to configure Brighter. If you want to use an alternative DI container then see the section [How Configuration Works](https://github.com/BrighterCommand/Docs/blob/master/contents/HowConfigurationWorks.md)

We divide configuration into two sections, depending on your requirements:

* [**Configuring The Command Processor**](#configuring-the-command-processor): This section covers configuring the **Command Processor**. Use this if you want to dispatch requests to handlers, or publish messages from your application on an external bus
* [**Configuring The Service Activator**](#configuring-the-service-activator): This section covers configuring the **Service Activator**. Use this if you want to read messages from a transport (and then dispatch to handlers).

## **Configuring The Command Processor**

### **Command Processor Service Collection Extensions**

Brighter's package:

* **Paramore.Brighter.Extensions.DependencyInjection**

provides extension methods for **ServiceCollection** that can be used to add Brighter to the .NET Core DI Framework.

By adding the package you can call the **AddBrighter()** extension method.

If you are using a **Startup** class's **ConfigureServices** method call the following:

```csharp
public void ConfigureServices(IServiceCollection services)
{
    services.AddBrighter(...)
}

```

if you are using .NET 6 you can make the call directly on your **HostBuilder**'s Services property.

The **AddBrighter()** method takes an **`Action<BrighterOptions>`** delegate. The extension method supplies the delegate with a **BrighterOptions** object that allows you to configure how Brighter runs.

The **AddBrighter()** method returns an **IBrighterBuilder** interface. **IBrighterBuilder** is a [fluent interface](https://en.wikipedia.org/wiki/Fluent_interface) that you can use to configure additional Brighter properties (see [Brighter Builder Fluent Interface](#brighter-builder-fluent-interface)).

#### **Adding Polly Policies**

Brighter uses Polly policies for both internal reliability, and to support adding a custom policy to a handler for reliability.

To use a Polly policy with Brighter you need to register it first with a Polly **PolicyRegistry**. In this example we register both Synchronous and Asynchronous Polly policies with the registry.

```csharp
    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 retryPolicyAsync = Policy.Handle<Exception>()
        .WaitAndRetryAsync(new[] { TimeSpan.FromMilliseconds(50), TimeSpan.FromMilliseconds(100), TimeSpan.FromMilliseconds(150) });
    
    var circuitBreakerPolicyAsync = Policy.Handle<Exception>().CircuitBreakerAsync(1, TimeSpan.FromMilliseconds(500));

    var policyRegistry = new PolicyRegistry()
    {
        { "SyncRetryPolicy", retryPolicy },
        { "SyncCircuitBreakerPolicy", circuitBreakerPolicy },
        { "AsyncRetryPolicy", retryPolicyAsync },
        { "AsyncCircuitBreakerPolicy", circuitBreakerPolicyAsync }
    };

```

And you can use them in you own handler like this:

```csharp
internal class MyQoSProtectedHandler : RequestHandler<MyCommand>
{
    static MyQoSProtectedHandler()
    {
        ReceivedCommand = false;
    }

    [UsePolicy(policy: "SyncRetryPolicy", step: 1)]
    public override MyCommand Handle(MyCommand command)
    {
        /*Do work that could throw error because of distributed computing reliability*/
    }
}
```

See the section [Policy Retry and Circuit Breaker](https://github.com/BrighterCommand/Docs/blob/master/contents/PolicyRetryAndCircuitBreaker.md) for more on using Polly policies with handlers.

With the Polly Policy Registry filled, you need to tell Brighter where to find the Policy Registry:

```csharp
public void ConfigureServices(IServiceCollection services)
{
    services.AddBrighter(options =>
        options.PolicyRegistry = policyRegistry
    )
}

```

#### **Configuring Lifetimes**

Brighter can register your _Request Handlers_ and _Message Mappers_ for you (see [IBrighter Builder Fluent Interface](#ibrighterbuilder-fluent-interface)). When we register types for you with ServiceCollection, we need to register them with a given lifetime (see [Dependency Injection Service Lifetimes](https://docs.microsoft.com/en-us/dotnet/core/extensions/dependency-injection#service-lifetimes)).

We also allow you to set the lifetime for the CommandProcessor.

We recommend the following lifetimes:

* If you are using _Scoped_ lifetimes, for example with EF Core, make your _Request Handlers_ and your _Command Processor_ Scoped as well.
* If you are not using _Scoped_ lifetimes you can use _Transient_ lifetimes for _Request Handlers_ and a _Singleton_ lifetime for the _Command Processor_.
* Your _Message Mappers_ should not have state and can be _Singletons_.

(Be cautious about using _Singleton_ lifetimes for _Request Handlers_. Even if your _Request Handler_ is stateless today, and so does not risk carrying state across requests, a common bug is that state is added to an existing _Request Handler_ which has previously been registered as a _Singleton_.)

You configure the lifetimes for the different types that Brighter can create at run-time as follows:

```csharp
public void ConfigureServices(IServiceCollection services)
{
    services.AddBrighter(options =>
        options.HandlerLifetime = ServiceLifetime.Scoped;
        options.CommandProcessorLifetime = ServiceLifetime.Scoped;
        options.MapperLifetime = ServiceLifetime.Singleton;
    );
}

```

### **Brighter Builder Fluent Interface**

#### **Type Registration**

The **IBrighterBuilder** fluent interface can scan your assemblies for your _Request Handlers_ (inherit from **IHandleRequests<>** or **IHandleRequestsAsync<>**) and _Message Mappers_ (inherit from **IAmAMessageMapper<>**) and register then with the **ServiceCollection**. This is the most common way to register your code.

```csharp
public void ConfigureServices(IServiceCollection services)
{
    services.AddBrighter(...)
        .AutoFromAssemblies();
}

```

The code scans any loaded assemblies. If you need to register types from assemblies that are not yet loaded, you can provide a list of additional assemblies to scan as an argument to the call to **AutoFromAssemblies()**.

```csharp
public void ConfigureServices(IServiceCollection services)
{
    services.AddBrighter(...)
        .AutoFromAssemblies(typeof(MyRequestHandlerAsync).Assembly);
}

```

Instead of using **AutoFromAssemblies** you can exert more fine-grained control over the registration, by explicitly registering your _Request Handlers_ and _Message Mappers_. We don't recommend this, but make it available for cases where the automatic registration does not meet your needs.

* **MapperRegistryFromAssemblies()**, **HandlersFromAssemblies()** and **AsyncHandlersFromAssemblies** are the methods called by **AutoFromAssemblies()** and can be called explicitly.
* **Handlers()**, **AsyncHandlers()** and **MapperRegistry()** accept an **Action<>** delegate that respectively provide you with **IAmASubscriberRegistry** or **IAmAnAsyncSubscriberRegistry** to register your RequestHandlers explicitly or a **ServiceCollectionMapperRegistry** to register your mappers. This gives you explicit control over what you register.

#### **Using an External Bus**

Using an _External Bus_ allows you to send messages between processes using a message-oriented middleware transport (such as RabbitMQ or Kafka). (For symmetry, we refer to the usage of the _Command Processor_ without an external bus as using an _Internal Bus_).

When raising a message on the _Internal Bus_, you use one of the following methods on the _Command Processor_:

* **Send()** and **SendAsync()** - Sends a _Command_ to one _Request Handler_.
* **Publish()** and **PublishAsync()** - Broadcasts an _Event_ to zero or more _Request Handlers_.

When raising a message on an _External Bus_, you use the following methods on the _CommandProcessor_:

* **Post()** and **PostAsync()** - Immediately posts a _Command_ or _Event_ to another process via the external Bus
* **DepositPost()** and **DepositPostAsync()** - Puts on or many _Command_(s) or _Event_(s) in the _Outbox_ for later delivery
* **ClearOutbox()** and **ClearOutboxAsync()** - Clears the _Outbox_, posting un-dispatched messages to another process via the _External Bus_.
* **ClearAsyncOutbox()** - Implicitly clears the **Outbox**, similar to above however allows bulk dispatching of messages onto a **Transport**.

The major difference here is whether or not you wish to use an _Outbox_ for Transactional Messaging. (See [Outbox Pattern](https://github.com/BrighterCommand/Docs/blob/master/contents/OutboxPattern.md) and [Brighter Outbox Support](https://github.com/BrighterCommand/Docs/blob/master/contents/BrighterOutboxSupport.md) for more on Brighter and the Outbox Pattern).

#### Configuring an External Bus

To use an _External Bus_, you need to supply Brighter with configuration information that tells Brighter what middleware you are using and how to find it. (You don't need to do anything to configure an _Internal Bus_, it is always available.)

The **IBrighterBuilder** interface returned from **AddBrighter** allows you to configure the properties of your external bus, by calling the **UseExternalBus** extension method. The UseExternalBus extension method takes a lambda function, whose only parameter is an **ExternalBusConfiguration**. The **ExternalBusConfiguration** lets you set properties such as

```csharp
private void ConfigureBrighter(IServiceCollection services)
{
    services.AddBrighter(options =>
        {
            ...
        })
        .UseExternalBus((configure) =>
        {
        })
        .AutoFromAssemblies();

```

#### \*\*Transports

_Transports_ are how Brighter supports specific Message-Oriented-Middleware (MoM). _Transports_ are provided in separate NuGet packages so that you can take a dependency only on the transport that you need. Brighter supports a number of different _transports_.

We use the naming convention **Paramore.Brighter.MessagingGateway.{TRANSPORT}** for _transports_ where {TRANSPORT} is the name of the middleware.

In this example we will use the transport for RabbitMQ, provided by the NuGet package:

* **Paramore.Brighter.MessagingGateway.RMQ**

See the documentation for detail on specific _transports_ on how to configure them for use with Brighter, for now it is enough to know that you need to provide a _Messaging Gateway_ which tells us how to reach the middleware and a _Publication_ which tells us how to configure the middleware.

#### **Publications**

A _Publication_ configures a transport for sending a message to it's associated MoM. So an **RmqPublication** configures how we publish a message to RabbitMQ. There are a number of common properties to all publications.

* **MakeChannels**: Do you want Brighter to create the infrastructure? Brighter can create infrastructure that it needs, and is aware of: **OnMissingChannel.Create**. So a publication can create the topic to send messages to. Alternatively if you create the channel by another method, such as IaaC, we can verify the infrastructure on startup: **OnMissingChannel.Validate**. Finally, you can avoid the performance cost of runtime checks by assuming your infrastructure exists: **OnMissingChannel.Assume**.
* **MaxOutstandingMessages**: How large can the number of messages in the Outbox grow before we stop allowing new messages to be published and raise an **OutboxLimitReachedException**.
* **MaxOutStandingCheckIntervalMilliSeconds**: How often do we check to see if the Outbox is full.
* **Topic**: A Topic is the key used within the MoM to route messages. Publishers publish to a topic and subscribers, subscribe to it. We use a class **RoutingKey** to encapsulate the identifier used for a topic. The name the MoM uses for a topic may vary. Kafka & SNS use _topic_ whilst RMQ uses _routingkey_

#### Producer Registry

In order to provide Brighter with the means to send a message via the transport, we need to provide it with an **IAmAProducerRegistry** for the transport you intend to use for the _External Bus_.

A **producer** is the transport specific code that you need to send messages; it implements **IAmAMessageProducer**.

We register a **producer** with a **producer registry**; it needs to implement **IAmAProducerRegistry** but usually you will use the provided **ProducerRegistry**. At runtime, we lookup the producer to use in the registry by **routing key** (aka topic).

Typically for a transport we implement a **producer registry factory**; it needs to implement **IAmAProducerRegistryFactory**. For example, for the RMQ transport, we provide **RmqProducerRegistryFactory**. A **producer registry factory** typically takes a **connection** to the broker and a collection of **publications**, and it iterates over the **publications** creating a producer for each one and registering it in a **producer registry**. It then returns a configured **producer registry**.

The following code shows an application using the RMQ transport support to create its **producer registry**.

```csharp
var producerRegistry = new RmqProducerRegistryFactory(
    new RmqMessagingGatewayConnection
    {
        AmpqUri = new AmqpUriSpecification(new Uri("amqp://guest:guest@localhost:5672")),
        Exchange = new Exchange("paramore.brighter.exchange"),
    },
    new RmqPublication[]
    {
        new RmqPublication
        {
            Topic = new RoutingKey("GreetingMade"),
            MaxOutStandingMessages = 5,
            MaxOutStandingCheckIntervalMilliSeconds = 500,
            WaitForConfirmsTimeOutInMilliseconds = 1000,
            MakeChannels = OnMissingChannel.Create
        }
    }
).Create();
```

#### **Bus Example**

Putting this together, an example configuration for an External Bus for a local RabbitMQ instance could look like this:

```csharp
public void ConfigureServices(IServiceCollection services)
{
    services.AddBrighter(...)
        .UseExternalBus((configure) =>
        {
            configure.ProducerRegistry = new RmqProducerRegistryFactory(
                new RmqMessagingGatewayConnection
                {
                    AmpqUri = new AmqpUriSpecification(new Uri("amqp://guest:guest@localhost:5672")),
                    Exchange = new Exchange("paramore.brighter.exchange"),
                },
                new RmqPublication[]{
                    new RmqPublication
                {
                    Topic = new RoutingKey("GreetingMade"),
                    MaxOutStandingMessages = 5,
                    MaxOutStandingCheckIntervalMilliSeconds = 500,
                    WaitForConfirmsTimeOutInMilliseconds = 1000,
                    MakeChannels = OnMissingChannel.Create
                }}
            ).Create();
        })
        .AutoFromAssemblies()

            ...
}
```

#### **Outbox Support**

If you intend to use Brighter's _Outbox_ support for Transactional Messaging then you need to provide us with details of your _Outbox_.

Brighter provides a number of _Outbox_ implementations for common Dbs (and you can write your own for a Db that we do not support). For this discussion we will look at Brighter's support for working with EF Core. See the documentation for working with specific _Outbox_ implementations.

EF Core supports a number of databases and you should pick the packages that match the Dy you want to use with EF Core. In this case we will choose MySQL.

For this we will need the _Outbox_ packages for the MySQL _Outbox_.

* **Paramore.Brighter.MySql**
* **Paramore.Brighter.Outbox.MySql**

For a given backing store the pattern should be Paramore.Brighter.{DATABASE} and Paramore.Brighter.Outbox.{DATABASE} where {DATABASE} is the name of the Db that you are using.

In addition for an ORM you will need to add the package that supports the ORM, in this case EF Core:

* **Paramore.Brighter.MySql.EntityFrameworkCore**

For a given ORM the pattern should be Paramore.Brighter.{ORM}.{DATABASE} where {ORM} is the ORM you are choosing and {DATABASE} is the Db you are using with the ORM.

#### Configuring the Outbox

To configure our _Outbox_ we need to use the **ExternalBusConfiguration**.

An Outbox has three pieces:

* The _Outbox_, which implements **IAmAnOutbox**. Brighter provides implementations for a range of common Dbs.
* The _Connection Provider_ which tells Brighter how to connect to the _Outbox_
* The _Transaction Provider_ which allows Brighter to participate in the same transaction that you update an entity with.

In this example, we want to use EF Core with an MySQL Outbox. See the documentation for Outboxes for specific configuration options.

```csharp
public void ConfigureServices(IServiceCollection services)
{
            
    var outboxConfiguration = new RelationalDatabaseConfiguration(DbConnectionString());
    services.AddSingleton<IAmARelationalDatabaseConfiguration>(outboxConfiguration);

    services.AddBrighter(...)
        .UseExternalBus((configure) =>
        {
            configure.Outbox = new MySqlOutbox(outboxConfiguration);
            configure.TransactionProvider = typeof(MySqlEntityFrameworkConnectionProvider<GreetingsEntityGateway>);
            configure.ConnectionProvider = typeof(MySqlConnectionProvider);
        })
        .AutoFromAssemblies();

        ...
}

```

Typically **DbConnectionString** would obtain the connection string for the Db from configuration.

#### Outbox Sweeper

Finally, if we want the _Outbox_ to use a background thread to clear un-dispatched items from the _Outbox_, and we do in most circumstances, we need to run an _Outbox Sweeper_ to do this work. (You can force an immediate clear within the code that produces the outgoing message using **ClearOutbox**, but you should still have a sweeper to guarantee it is sent if that call fails).

Typically you run one sweeper. Brighter does not have a distributed lock. As such, running a sweeper in every producer will cause issues as multiple sweepers may try to clear an outstanding message. The outbox documentation looks at your strategies for ensuring only one sweeper runs. For development purposes though, you may wish to add a sweeper to the instance that you are currently running.

To add the _Outbox Sweeper_ you will need to take a dependency on another NuGet package:

* **Paramore.Brighter.Extensions.Hosting**

You can then add a sweeper using "UseOutboxSweeper"

This results in:

```csharp
public void ConfigureServices(IServiceCollection services)
{
    services.AddBrighter(...)
        .UseExternalBus(...)
         .UseOutboxSweeper()
         .AutoFromAssemblies();
        ...
}

```

#### Request-Reply

(**UseExternalBus()** has optional parameters for use with Request-Reply support for some transports. We don't cover that here, instead see [Direct Messaging](https://github.com/BrighterCommand/Docs/blob/master/contents/Routing.md#direct-messaging) for more).

#### **Configuring JSON Serialization**

Brighter defines a set of serialization options for use when it needs to serialize messages to JSON. Internally we use these options in our transports, when serializing messages to an external bus and deserializing from an external bus. You may wish to use these options in your own [_Message Mapper_](https://github.com/BrighterCommand/Docs/blob/master/contents/MessageMappers.md) implementation.

By default our JSONSerialization Options are configured as follows:

```csharp
static JsonSerialisationOptions()
{
    var opts = new JsonSerializerOptions
    {
        PropertyNameCaseInsensitive = true,
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        NumberHandling = JsonNumberHandling.AllowReadingFromString,
        AllowTrailingCommas = true
    };

    opts.Converters.Add(new JsonStringConverter());
    opts.Converters.Add(new DictionaryStringObjectJsonConverter());
    opts.Converters.Add(new ObjectToInferredTypesConverter());
    opts.Converters.Add(new JsonStringEnumConverter());

    Options = opts;
}
```

You can use the **IBrighterBuilder** extension **ConfigureJsonSerialisation** to override these values. The method takes an **Action\<JsonSerialisationOptions>** lambda expression that allows you to override these defaults. For example:

```csharp

.ConfigureJsonSerialisation((options) =>
{
    options.PropertyNameCaseInsensitive = true;
})

```

If you want to use this configured set of JSON Serialization options in your own code, you can, by using the static property JsonSerialisationOptions.Options. For example:

```csharp
public GreetingMade MapToRequest(Message message)
{
    return JsonSerializer.Deserialize<GreetingMade>(message.Body.Value, JsonSerialisationOptions.Options);
}
```

#### Retry and Circuit Breaker with an External Bus

When sending a request via the External Bus we use a Polly policy internally to control Retry and Circuit Breaker in case the External Bus is not available. These policies have defaults but you can configure the behavior using the policy keys:

* **Paramore.RETRYPOLICY**
* **Paramore.CIRCUITBREAKER**

### **Putting It All Together**

Putting all this together, a typical configuration might looks as follows:

```csharp
public void ConfigureServices(IServiceCollection services)
{

    var outboxConfiguration = new RelationalDatabaseConfiguration(DbConnectionString());
    services.AddSingleton<IAmARelationalDatabaseConfiguration>(outboxConfiguration);

    services.AddBrighter(options =>
        {
            options.HandlerLifetime = ServiceLifetime.Scoped;
            options.MapperLifetime = ServiceLifetime.Singleton;
            options.PolicyRegistry = policyRegistry;
        })
        .ConfigureJsonSerialisation((options) =>
        {
            options.PropertyNameCaseInsensitive = true;
        })
       .UseExternalBus((configure) =>
        {
            configure.ProducerRegistry = new RmqProducerRegistryFactory(
                new RmqMessagingGatewayConnection
                {
                    AmpqUri = new AmqpUriSpecification(new Uri("amqp://guest:guest@localhost:5672")),
                    Exchange = new Exchange("paramore.brighter.exchange"),
                },
                new RmqPublication[]{
                    new RmqPublication
                {
                    Topic = new RoutingKey("GreetingMade"),
                    MaxOutStandingMessages = 5,
                    MaxOutStandingCheckIntervalMilliSeconds = 500,
                    WaitForConfirmsTimeOutInMilliseconds = 1000,
                    MakeChannels = OnMissingChannel.Create
                }}
            ).Create();
           configure.Outbox = new MySqlOutbox(outboxConfiguration);
           configure.TransactionProvider = typeof(MySqlEntityFrameworkConnectionProvider<GreetingsEntityGateway>);
           configure.ConnectionProvider = typeof(MySqlConnectionProvider);
        })
        .UseOutboxSweeper()
        .AutoFromAssemblies();
}

```

## **Configuring The Service Activator**

A _consumer_ reads messages from Message-Oriented Middleware (MoM), and a _producer_ puts messages onto the MoM for the _consumer_ to read.

A _consumer_ waits for messages to appear on the queue, reads them, and then calls your _Request Handler_ code to react. Because the •consumer\* runs your code in response to an external request, a message being placed on the External Bus, we call the component that listens for messages and dispatches them a [_Service Activator_](https://www.enterpriseintegrationpatterns.com/patterns/messaging/MessagingAdapter.html)

To use Brighter's Service Activator you will need to take a dependency on the NuGet package:

* **Paramore.Brighter.ServiceActivator**

### **ServiceActivator Service Collection Extensions**

We provide support for configuring .NET Core's **HostBuilder** as a _ServiceActivator_ for use with MoM. We use Brighter's Command Processor to dispatch the messages read by a _Dipatcher_. If you are not using **HostBuilder** then you will need to configure the Dispatcher yourself. See [How Configuring the Dispatcher Works](https://github.com/BrighterCommand/Docs/blob/master/contents/HowConfiguringTheDispatcherWorks.md) for more.

To use Brighter's _Service Activator_ with **HostBuilder** you will need to take a dependency on the following NuGet packages:

* **Paramore.Brighter.ServiceActivator.Extensions.Hosting**
* **Paramore.Brighter.ServiceActivator.Extensions.DependencyInjection**

These provide an extension method **AddServiceActivator()** that can be used to add Brighter to the .NET Core DI Framework.

By adding the package you can call the **AddServiceActivator()** extension method.

If you are using a **HostBuilder** class's **ConfigureServices** method call the following:

```csharp
private static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices(hostContext, services) =>
        {
            services.AddServiceActivator(...)
        }

```

if you are using .NET 6 you can make the call direction on your **HostBuilder**'s Services property.

The **AddServiceActivator()** method takes an **`Action<ServiceActivatorOptions>`** delegate. The extension method supplies the delegate with a **ServiceActivatorOptions** object that allows you to configure how Brighter runs.

The **AddServiceActivator()** method returns an **IBrighterBuilder** interface. **IBrighterBuilder** is a [fluent interface](https://en.wikipedia.org/wiki/Fluent_interface) that you can use to configure Brighter _Command Processor_ properties. It is discussed above at [Brighter Builder Fluent Interface](#brighter-builder-fluent-interface)) and the same options apply. We discuss one additional option that becomes important when receiving requests the _Inbox_ in [Additional Brighter Builder Options](https://github.com/BrighterCommand/Docs/blob/master/contents/BasicConfiguration.md#the-inbox).

#### **Subscriptions**

When configuring your application's _Service Activator_, your _Subscriptions_ indicate configure how your application will receive messages from the associated MoM queues or streams.

All _Subscriptions_ lets you configure the following common properties.

* **Buffer Size**: The number of messages to hold in memory. Where the buffer is not shared, a single thread or Performer can access these; where the buffer is shared, multiple threads can access the same buffer of work. Work in a buffer is locked on queue based middleware, and thus not available to other consumers (threads or process depending if the buffer is shared or not) until _Acknowledged_ or _Rejected_.
* **Channel Factory**: Creates or finds the necessary infrastructure for messaging on the MoM and wraps it in an object.
* \*_Channel Name_: If queues are primitives in the MoM this names the queue, otherwise just used for diagnostics.
* **Channel Failure Delay**: How long should we delay if a channel fails before trying again, to give problems time to clear.
* **Data Type**: We use a [Datatype Channel](https://www.enterpriseintegrationpatterns.com/DatatypeChannel.html). What is the type of this channel?
* **Empty Channel Delay**: If there are no messages in the queue or stream when we read, how long should we pause before reading again?
* **MakeChannels**: Do you want Brighter to create the infrastructure? Brighter can create infrastructure that it needs, and is aware of: **OnMissingChannel.Create**. So a subscription can create the topic to send messages to, and any subscription to that topic required by the MoM, including a queue (which uses the _Channel Name_). Alternatively if you create the channel by another method, such as IaaC, we can verify the infrastructure on startup: **OnMissingChannel.Validate**. Finally, you can avoid the performance cost of runtime checks by assuming your infrastructure exists: **OnMissingChannel.Assume**.
* **Name**: What do we call this subscription for diagnostic purposes.
* **NoOfPerformers**: Effectively, how many threads do we use to read messages from the queue. As Brighter uses a Single-Threaded Apartment model, each thread has it's own message pump and is thus an in-process implementation of the [Competing Consumers](https://www.enterpriseintegrationpatterns.com/CompetingConsumers.html) pattern.
* **RequeueCount**: How many times can you retry a message before we declare it a poison pill message?
* **RequeueDelayInMilliseconds**: When we requeue a message how long should we delay it by?
* **RoutingKey**: The identifier used to routed messages to subscribers on MoM. You publish to this, and subscriber from this. This has different names; in Kafka or SNS this is a Topic, in RMQ this is the routing key.
* **RunAsync**: Is this an async pipeline? Your pipeline must be sync or async. An async pipeline can increase throughput where a handler is I/O bound by allowing the message pump to read another message whilst we await I/O completion. The cost of this is that strict ordering of messages will now be lost as processing of I/O bound requests may complete out-of-sequence. Brighter provides its own synchronization context for async operations. We recommend scaling via increasing the number of performers, unless you know that I/O is your bottleneck.
* **TimeoutInMilliseconds**: How long does a read 'wait' before assuming there are no pending messages.
* **UnaceptableMessageLimit**: Brighter will ack a message that throws an unhandled exception, thus removing it from a queue.

For a more detailed discussion of using Requeue (with Delay) for Handler failure, (**RequeueCount** and **RequeueDelayInMilliseconds**) along with termination of a consumer due to message failure (**UnacceptableMessageLimit**) see [Handler Failure](https://github.com/BrighterCommand/Docs/blob/master/contents/HandlerFailure.md)

In addition, individual transports that provide access to specific MoM sub-class _Subscription_ to provide properties unique to the chosen middleware. We discuss those under a section for that transport.

For RabbitMQ for example, this would look like this:

```csharp
private static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices(hostContext, services) =>
        {
            ConfigureBrighter(hostContext, services);
        }

private static void ConfigureBrighter(HostBuilderContext hostContext, IServiceCollection services)
{
    var subscriptions = new Subscription[]
    {
        new RmqSubscription<GreetingMade>(
            new SubscriptionName("paramore.sample.salutationanalytics"),
            new ChannelName("SalutationAnalytics"),
            new RoutingKey("GreetingMade"),
            runAsync: true,
            timeoutInMilliseconds: 200,
            isDurable: true,
            makeChannels: OnMissingChannel.Create), //change to OnMissingChannel.Validate if you have infrastructure declared elsewhere
    };

    services.AddServiceActivator(options =>
        {
            options.Subscriptions = subscriptions;
        })
}

...

```

#### **Gateway Connections & Channel Factories**

A _Gateway Connection_ tells Brighter how to connect to MoM for a particular transport. The transport package will contain a _Gateway Connection_, you need to provide the information to connect to your middleware (URIs, ports, credentials etc.) Your transport package provides a _Gateway Connection_

A _Channel Factory_ connects Brighter to MoM. Depending on the configuration settings for your _Subscription_ it may create the required primitives (topics/routing keys, queues, streams) on MoM or simply attach to ones that you have created via Infrastructure as Code (IaC). Your transport provides a _Channel Factory_ and you need to pass it a _Gateway Connection_.

For RabbitMQ, this would look like:

```csharp
private static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices(hostContext, services) =>
        {
            ConfigureBrighter(hostContext, services);
        }

private static void ConfigureBrighter(HostBuilderContext hostContext, IServiceCollection services)
{

    var rmqConnection = new RmqMessagingGatewayConnection
    {
        AmpqUri = new AmqpUriSpecification(new Uri($"amqp://guest:guest@local:5672")),
        Exchange = new Exchange("paramore.brighter.exchange")
    };

    var rmqMessageConsumerFactory = new RmqMessageConsumerFactory(rmqConnection);

    services.AddServiceActivator(options =>
        {
             options.ChannelFactory = new ChannelFactory(rmqMessageConsumerFactory);
        })
}

...

```

#### **Configuring Service Activator Lifetimes**

Under the hood your _Service Activator_ uses a _Command Processor_ and you will need to configure lifetimes [as discussed above](#configuring-lifetimes).

An additional requirement is configuring the lifetime of the _Command Processor_ itself. Within the context of an ASP.NET application, configuring the lifetime of the **Command Processor** relies on ASP.NET creating an instance of the _Command Processor_ in a request pipeline. When you are using _Service Activator_ there is no ASP.NET pipeline, instead Brighter's _Dispatcher_ manages the lifetime of the _Command Processor_ that we pass a request to. By setting the **ServiceActivatorOptions.UseScoped** field to true, you instruct _Brighter_ to use a new _Command Processor_ instance for each request. This is important if you take the _Command Processor_ as a dependency in any of your _Request Handlers_ with a **Scoped** lifetime. If in doubt, just set **ServiceActivatorOptions.UseScoped** field to true.

```csharp
private static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices(hostContext, services) =>
        {
            ConfigureBrighter(hostContext, services);
        }

private static void ConfigureBrighter(HostBuilderContext hostContext, IServiceCollection services)
{
    services.AddServiceActivator(options =>
        {
            options.UseScoped = true;
            options.HandlerLifetime = ServiceLifetime.Scoped;
            options.MapperLifetime = ServiceLifetime.Singleton;
            options.CommandProcessorLifetime = ServiceLifetime.Scoped;
    })
}

...

```

### **Service Activator Brighter Builder Fluent Interface**

The call to **AddServiceActivator()** returns an **IBrighterBuilder** fluent interface. This means that you can use any of the options described in [Brighter Build Fluent Interfaces](#brighter-builder-fluent-interface) to configure the associated _Command Processor_ such as scanning assemblies for _Request Handlers_ and adding an _External Bus_ and _Outbox_.

An option is intended for the context of a Service Activator is described below.

#### **Inbox**

As described in the [Outbox Pattern](https://github.com/BrighterCommand/Docs/blob/master/contents/OutboxPattern.md) an _Outbox_ offers **Guaranteed, At Least Once** delivery. It explicitly may result in you sending duplicate messages. In addition, MoM tends to offer "At Least Once" guarantees only, further creating the risk that you will receive a duplicate message.

If the request is not idempotent, you can use an Inbox to de-duplicate it. See [Inbox Support](https://github.com/BrighterCommand/Docs/blob/master/contents/BrighterInboxSupport.md) for more.

Configuring an _Inbox_ has two elements. The first is the type of _Inbox_, the second configuration for the _Inbox_ behavior.

Brighter provides a number of _Inbox_ implementations for common Dbs (and you can write your own for a Db that we do not support). For this discussion we will look at Brighter's support for working with MySQL. See the documentation for working with specific _Inbox_ implementations.

For this we will need the _Inbox_ packages for the MySQL _Inbox_.

* **Paramore.Brighter.Inbox.MySql**

For a given backing store the pattern should be Paramore.Brighter.Inbox.{DATABASE} where {DATABASE} is the name of the Db that you are using.

To configure our _Inbox_ we then need to use the UseExternalInbox method call and pass in an instance of a class that implements **IAmAnInbox**, taken from our package, and an instance of **InboxConfiguration** that tells Brighter how we want to use the Inbox.

For _Inbox Configuration_ you set the following properties:

* **ActionOnExists**: What do we do if the request has been handled? The default,**OnceOnlyAction.Throw** is to throw a **OnceOnlyException**. If you take no other action this will cause the message to be rejected and sent to a DLQ if one is configured (See [Handler Failure](https://github.com/BrighterCommand/Docs/blob/master/contents/HandlerFailure.md)). The alternative is **OnceOnlyAction.Warn** simply logs that the request is a duplicate, but takes no other action.
* **OnceOnly**: This defaults to _true_ and will check for a duplicate and take the action indicated by **ActionOnExists**. If _false_ the _Inbox_ will record the request, but will take no further action. (This tends to be set to _false_ if you are using the _Inbox_ to record what requests caused current state only and not de-duplicate).
* **Scope**: This indicates the type of request (_Command_ or _Event_) to store in the _Inbox_. By default this is set to **InboxScope.All** and captures everything but you can be explicit and just capture **InboxScope.Commands** or **InboxScope.Events**. (This tends to be set to **InboxScope.Commands** when only commands cause changes to state that are not idempotent).
* **Context**: Used to uniquely identify receipt of this request via this handler. If you are recording _Events_ and have multiple handlers, then the first event handler to receive the message will block the others from doing so, unless you disambiguate the handler identity by supplying a context method.

A typical _Inbox_ configuration for MySQL would be:

```csharp
private static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices(hostContext, services) =>
        {
            ConfigureBrighter(hostContext, services);
        }

private static void ConfigureBrighter(HostBuilderContext hostContext, IServiceCollection services)
{
    services.AddServiceActivator(options =>
        {   
            ...
            options.InboxConfiguration =  new InboxConfiguration(
                    inbox: new MySqlInbox(new RelationalDatabaseConfiguration(DbConnectionString()))
                    scope: InboxScope.Commands,
                    onceOnly: true,
                    actionOnExists: OnceOnlyAction.Throw
        )})
;
}

...

```

Typically **DbConnectionString** would obtain the connection string for the Db from configuration.

### Running Service Activator

To run _Service Activator_ we add it as a [Hosted Service](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-6.0\&tabs=visual-studio).

We provide the class **ServiceActivatorHostedService** for this in the NuGet package:

* **Paramore.Brighter.ServiceActivator.Extensions.Hosting**

The **ServiceActivatorHostedService** calls the **Dispatcher.Receive** method which starts message pumps for the configured _Subscriptions_.

```csharp
private static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices(hostContext, services) =>
        {
            ConfigureBrighter(hostContext, services);
        }

private static void ConfigureBrighter(HostBuilderContext hostContext, IServiceCollection services)
{
    ...

    services.AddHostedService<ServiceActivatorHostedService>();
}

...

```

On shutdown Brighter will allow the current _Request Handler_ to complete, then end the message pump loop and exit. If you have long-running handlers it is possible that they will not complete in the default 5s for graceful shutdown of the MS Generic Host. In this case, you need to [increase the timeout](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-6.0#shutdowntimeout) of the host shutdown.

```csharp
private static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices(hostContext, services) =>
        {
            services.Configure<HostOptions>(options =>
            {
                options.ShutdownTimeout = TimeSpan.FromSeconds(20);
            });
            ConfigureBrighter(hostContext, services);
        }

private static void ConfigureBrighter(HostBuilderContext hostContext, IServiceCollection services)
{
    ...

    services.AddHostedService<ServiceActivatorHostedService>();
}

```

### A Complete Service Activator Example

When all of the relevant configuration sections are added together, your code will look something like this, with variations for your transport and stores.

```csharp
private static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices(hostContext, services) =>
        {
            services.Configure<HostOptions>(options =>
            {
                options.ShutdownTimeout = TimeSpan.FromSeconds(20);
            });
            ConfigureBrighter(hostContext, services);
        }

private static void ConfigureBrighter(HostBuilderContext hostContext, IServiceCollection services)
{
   var subscriptions = new Subscription[]
    {
        new RmqSubscription<GreetingMade>(
            new SubscriptionName("paramore.sample.salutationanalytics"),
            new ChannelName("SalutationAnalytics"),
            new RoutingKey("GreetingMade"),
            runAsync: true,
            timeoutInMilliseconds: 200,
            isDurable: true,
            makeChannels: OnMissingChannel.Create), //change to OnMissingChannel.Validate if you have infrastructure declared elsewhere
    };

    var rmqConnection = new RmqMessagingGatewayConnection
    {
        AmpqUri = new AmqpUriSpecification(new Uri($"amqp://guest:guest@localhost:5672")),
        Exchange = new Exchange("paramore.brighter.exchange")
    };

    var rmqMessageConsumerFactory = new RmqMessageConsumerFactory(rmqConnection);

    services.AddServiceActivator(options =>
    {
        options.Subscriptions = subscriptions;
        options.ChannelFactory = new ChannelFactory(rmqMessageConsumerFactory);
        options.UseScoped = true;
        options.HandlerLifetime = ServiceLifetime.Scoped;
        options.MapperLifetime = ServiceLifetime.Singleton;
        options.CommandProcessorLifetime = ServiceLifetime.Scoped;
        options.PolicyRegistry = new SalutationPolicy();
        options.InboxConfiguration =  new InboxConfiguration(
            inbox: new MySqlInbox(new RelationalDatabaseConfiguration(DbConnectionString()))
            scope: InboxScope.Commands,
            onceOnly: true,
            actionOnExists: OnceOnlyAction.Throw
        );
    })
    .UseExternalBus((configure) =>
    {
        configure.ProducerRegistry = producerRegistry;
        configure.Outbox = outbox;
        configure.TransactionProvider = transactionProvider;
        configure.ConnectionProvider = connectionProvider;
    })
    .AutoFromAssemblies();
    
    services.AddHostedService<ServiceActivatorHostedService>();

}

```

## Samples

Brighter includes a comprehensive set of [Samples](https://github.com/BrighterCommand/Brighter/tree/master/samples) in its main repo that you can review for clarity on how Brighter works and should be configured.
