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
  • Using the Feature Switch Attribute
  • Building a config for Feature Switches with FluentConfigRegistryBuilder
  • Implementing a custom Feature Switch Registry
  • Setting Feature Switching Registry

Was this helpful?

Edit on GitHub
  1. Brighter Request Handlers and Middleware Pipelines

Feature Switches

PreviousFailure and FallbackNextOutbox Support

Last updated 2 years ago

Was this helpful?

We provide a FeatureSwitch Attribute and FeatureSwitchAsync Attribute that you can use on your IHandleRequests<TRequest>.Handle() method, and IHandleRequests<TRequest>.HandleAysnc() method. The FeatureSwitch Attribute and FeatureSwitchAsync Attribute that you have configured will determine whether or not the IHandleRequests<TRequest>.Handle() and IHandleRequests<TRequest>.HandleAsync() will be executed.

Using the Feature Switch Attribute

By adding the FeatureSwitch Attribute or FeatureSwitchAsync Attribute, you instruct the Command Processor to do one of the following:

  • run the handler as normal, this is FeatureSwitchStatus.On.

  • not execute the handler, this is FeatureSwitchStatus.Off.

  • detemine whether to run the handler based on a Feature Switch Registry, .

In the following example, MyFeatureSwitchedHandler will only be run if it has been configured in the Feature Switch Registry and set to FeatureSwitchStatus.On.

class MyFeatureSwitchedHandler : RequestHandler<MyCommand>
{
    [FeatureSwitch(typeof(MyFeatureSwitchedHandler), FeatureSwitchStatus.Config, step: 1)]
    public override MyCommand Handle (MyCommand command)
    {
        /* Do work */
        return base.Handle(command);
    }
}

In the second example, MyIncompleteHandlerAsync will not be run in the pipeline.

class MyIncompleteHandlerAsync : RequestHandlerAsync<MyCommand>
{
    [FeatureSwitchAsync(typeof(MyIncompleteHandlerAsync), FeatureSwitchStatus.Off, step: 1)]
    public override Task<MyCommand> HandleAsync(MyCommand command, CancellationToken cancellationToken = default)
    {
        /* Nothing implmented so we're skipping this handler */
        return await base.HandleAsync(command, cancellationToken);
    }
}

Building a config for Feature Switches with FluentConfigRegistryBuilder

We provide a FluentConfigRegistryBuilder to build a mapping of request handlers to FeatureSwitchStatus. For each Handler that you wish to feature switch you supply a type and a status using a fluent API. The valid statuses used in the builder are FeatureSwitchStatus.On and FeatureSwitchStatus.Off.

var featureSwitchRegistry = FluentConfigRegistryBuilder
                            .With()
                            .StatusOf<MyFeatureSwitchedHandler>().Is(FeatureSwitchStatus.On)
                            .StatusOf<MyIncompleteHandler>().Is(FeatureSwitchStatus.Off)
                            .Build();

Implementing a custom Feature Switch Registry

The MissingConfigStrategy determines how the Command Processor should behave when a Handler is decorated with a FeatureSwitch Attribute that is set to FeatureSwitchStatus.Config does not exist in the registry.

Your implementation of the StatusOf method is used to determine the FeatureSwitchStatus of the Handler type that is passed in as a parameter. How you store and retrieve these configurations is then up to you.

In the following example there are two FeatureSwitches configured in the AppSettings.config. We then build an AppSettingsConfigRegistry. The StatusOf method is implemetned to read the config from the App Settings and return the status for the given type.

<appSettings>
    <add key="FeatureSwitch::Namespace.MyFeatureSwitchedHandler" value="on"/>
    <add key="FeatureSwitch::Namespace.MyIncompleteHandler" value="off"/>
</appSettings>    
class AppSettingsConfigRegistry : IAmAFeatureSwitchRegistry
{
    public MissingConfigStrategy MissingConfigStrategy { get; set; }

    public FeatureSwitchStatus StatusOf(Type handler)
    {            
        var configStatus = ConfigurationManager.AppSettings[$"FeatureSwitch::{handler}"].ToLower();

        switch (configStatus)
        {
            case "on":
                return FeatureSwitchStatus.On;
            case "off":
                return FeatureSwitchStatus.Off;
            default:
                return MissingConfigStrategy is MissingConfigStrategy.SilentOn 
                            ? FeatureSwitchStatus.On 
                            : MissingConfigStrategy is MissingConfigStrategy.SilentOff 
                                ? FeatureSwitchStatus.Off 
                                : throw new InvalidOperationException($"No Feature Switch configuration for {handler} specified");                    
        }
    }
}

Setting Feature Switching Registry

We associate a Feature Switch Registry with a Command Processor by passing it into the constructor of the Command Processor. For convenience, we provide a Commmand Processor Builder that helps you configure new instances of Command Processor.

var featureSwitchRegistry = FluentConfigRegistryBuilder
                            .With()
                            .StatusOf<MyFeatureSwitchedConfigHandler>().Is(FeatureSwitchStatus.Off)
                            .Build();

var builder = CommandProcessorBuilder
                    .With()
                    .Handlers(new HandlerConfiguration(_registry, _handlerFactory))
                    .DefaultPolicy()
                    .NoTaskQueues()
                    .ConfigureFeatureSwitches(fluentConfig)
                    .RequestContextFactory(new InMemoryRequestContextFactory());

var commandProcessor = builder.Build();

The FluentConfigRegistryBuilder provides compile time configuration of FeatureSwitch Attributes. If this is not suitable to your needs then you can write you own Feature Switch Registry using the interface. The two requirements of this interface is a , and an implementation of StatusOf(Type type) which returns a FeatureSwitchStatus.

creating of which is described later
IAmAFeatureSwitchRegistry
MissingConfigStrategy