Exploring CQRS within the Brighter .NET open source project
There's a ton of cool new .NET Core open source projects lately, and I've very much enjoyed exploring this rapidly growing space. Today at lunch I was checking out a project called "Brighter." It's actually been around in the .NET space for many years and is in the process of moving to .NET Core for greater portability and performance.
Brighter is a ".NET Command Dispatcher, with Command Processor features for QoS (like Timeout, Retry, and Circuit Breaker), and support for Task Queues"
Whoa, that's a lot of cool and fancy words. What's it mean? The Brighter project is up on GitHub incudes a bunch of libraries and examples that you can pull in to support CQRS architectural styles in .NET. CQRS stands for Command Query Responsibility Segregation. As Martin Fowler says, "At its heart is the notion that you can use a different model to update information than the model you use to read information." The Query Model reads and the Command Model updates/validates. Greg Young gives the first example of CQRS here. If you are a visual learner, there's a video from late 2015 where Ian Cooper explains a lot of this a the London .NET User Group or an interview with Ian Cooper on Channel 9.
Brighter also supports "Distributed Task Queues" which you can use to improve performance when you're using a query or integrating with microservices.
When building distributed systems, Hello World is NOT the use case. BUT, it is a valid example in that it strips aside any business logic and shows you the basic structure and concepts.
Let's say there's a command you want to send. The GreetingCommand. A command can be any write or "do this" type command.
internal class GreetingCommand : Command
{
public GreetingCommand(string name)
:base(new Guid())
{
Name = name;
}
public string Name { get; private set; }
}
Now let's say that something else will "handle" these commands. This is the DoIt() method. No where do we call Handle() ourselves. Similar to dependency injection, we won't be in the business of calling Handle() ourselves; the underlying framework will abstract that away.
internal class GreetingCommandHandler : RequestHandler<GreetingCommand>
{
[RequestLogging(step: 1, timing: HandlerTiming.Before)]
public override GreetingCommand Handle(GreetingCommand command)
{
Console.WriteLine("Hello {0}", command.Name);
return base.Handle(command);
}
}
We then register a factory that takes types and returns handlers. In a real system you'd use IoC (Inversion of Control) dependency injection for this mapping as well.
Our Main() has a registry that we pass into a larger pipeline where we can set policy for processing commands. This pattern may feel familiar with "Builders" and "Handlers."
private static void Main(string[] args)
{
var registry = new SubscriberRegistry();
registry.Register<GreetingCommand, GreetingCommandHandler>();
var builder = CommandProcessorBuilder.With()
.Handlers(new HandlerConfiguration(
subscriberRegistry: registry,
handlerFactory: new SimpleHandlerFactory()
))
.DefaultPolicy()
.NoTaskQueues()
.RequestContextFactory(new InMemoryRequestContextFactory());
var commandProcessor = builder.Build();
...
}
Once we have a commandProcessor, we can Send commands to it easier and the work will get done. Again, how you ultimately make the commands is up to you.
commandProcessor.Send(new GreetingCommand("HanselCQRS"));
Methods within RequestHandlers can also have other behaviors associated with them, as in the case of "[RequestLogging] on the Handle() method above. You can add other stuff like Validation, Retries, or Circuit Breakers. The idea is that Brighter offers a pipeline of handlers that can all operate on a Command. The Celery Project is a similar project except written in Python. The Brighter project has stated they have lofty goals, intending to one day handle fault tolerance like Netflix's Hystrix project.
One of the nicest aspects to Brighter is that it's prescriptive but not heavy-handed. They say:
Brighter is intended to be a library not a framework, so it is consciously lightweight and divided into packages that allow you to consume only those facilities that you need in your project.
Moving beyond Hello World, there are more fleshed out examples like a TaskList with a UI, back end Http API, a Mailer service, and core library.
Be sure to explore Brighter's excellent documentation and examples, but be aware, this is a project under active development. Perhaps if you're new to OSS, if you find a broken link or two or a misspelling, you can do Your First Pull Request with a small fix?
Do be aware, again, that CQRS is not for every project. It's non-trivial and it's a "mental leap" as Martin Fowler puts it. If you buy in, you're adding complexity...for a reason. Keep your eyes open and do your research. It's a great pattern if you have a high performance/volume application that struggles with write concurrency or a flaky backend.
In fact there are quite a few mature CQRS libraries in the .NET open source space. I'll explore a few - which are your favorites?
Sponsor: Seq is simple centralized logging, on your infrastructure, with great support for ASP.NET Core and Serilog. Version 4 adds integrated dashboards and alerts - check it out!
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
It's basically impossible to use sequential ids, if your building a distributed system and your generating the IDs in client or application interacting with the distributed system. You don't really want to wait for a reply.
Issue with fragmentation can be improved using comb guid, HiLo generation or something like NewId.
I wrote a quite complex example a few years ago about cqrs with event sourcing using NServiceBus and EventStore. Also a few blog posts explaining it.
Hope you like it.
https://github.com/pablocastilla/CQRS-NServiceBus-EventStore-ElasticSearch
https://pablocastilla.wordpress.com/2014/09/22/cqrs-with-event-sourcing-using-nservicebus-event-store-elastic-search-angularjs-and-asp-net-mvc/
Mediatr has a similar model for command and handler seperation, along with a pipeline for orthogonal concerns to Brighter. There are some syntactic differences.
The main differences are (1) that we also support task queues i.e. running the handler asynchronously using a queue to provide availablility (both throttling and guaranteed delivery) and (2) we tend to use our sister project Darker (https://github.com/BrighterCommand/Darker) to do the query side, allowing us to seperate some of the requirements.
But, Mediatr is a great alternative (and there are other projects like Mass Transit and Rebus that you can check out in this space too).
Ian
Reviewing your post on Sept 10th 2009 when the codeplex foundation was created so much of an open source perspective has increasingly found resonance with Microsoft. However for whatever that means - how will advanced search in itself on github be able to bring out the sense of a community continuity - the creativity and synergy of an awareness of the Microsoft language category that you are suggesting in this post - other than by way of the threads you have realized over time.
I indeed explained myself "not clear enough" or not extensive enough... (I'm not a native English speaker).
I'm aware strict sequential ID's are not feasible in this context and wasn't suggesting they should be strict sequential (which is a bottle neck in distributed systems). I just wanted to make clear that it's better to have an ID that is not "random" like a GUID because it is a disaster for fragmentation in your database. Twitter snowflake ID concept (or other similar concepts) is made in the context of distributed ID generation (without central bottleneck) with a garantuee for uniqueness, but, it still has a certain sequential structure (not strict, so the next is not +1 after the other) and grouping structure, which is a lot better to store in databases in terms of indexing and perforamance.
We had this experience in a system where we originally used GUIDs for events, and replaced the by a variant on Twitter snowflake and had a major increase in system performance, and almost no fragmentation on the DB. Just want to point out GUIDs aren't really nice for DB's when used as keys, and there are really good alternatives when you want to make these kind of distributed systems.
public GreetingCommand(string name)
:base(new Guid())
It should be this:
public GreetingCommand(string name)
:base(Guid.NewGuid())
As you're no doubt aware, this:
new Guid()produces an empty GUID, i.e. all zeros:
00000000-0000-0000-0000-000000000000
Comments are closed.
you might want to check Mediatr which is maintained by Jimmy Bogard, the guy who's also doing Automapper. Don't know how it compares to Brighter, but after your article I will certainly investigate Brighter.
Also, using a GUID as a unique ID is often not desirable in this context and a more sequential ID is advised (like a custom (Twitter) snowflake ID for example). After all, CQRS is used a lot in combination with event sourcing, and, when storing things in a SQL DB, GUIDs are painfull. A more sequential ID has less fragmentation and speeds up the consolidation of events (e.g. to build up aggregates or snapshots).
Regards,
Wim