TL;DR: A single Azure Service Bus topic can be a reasonable starting point for one-to-many messaging. The topic receives published messages, and subscriptions provide separate delivery views for consumers. As the number of subscriptions, filters, and messages grows, the shared topic can become a place where routing work and storage pressure meet. Splitting event streams across topics may help, but adding entities alone does not accelerate a system. This post is part of a short series on Azure...
Azure Service Bus: Count your filters
TL;DR: Azure Service Bus can publish one message to a topic and deliver it to multiple consumers. A topic is the shared destination, a subscription is a consumer-specific view, and a filter decides whether a message is copied to that subscription. In high-throughput systems, the number of subscription rules can matter more than the filter type itself. This is the first post in a short series on Azure Service Bus topology under load. The series looks at filter count, subscription fan-out (one...
The scheduler is part of your message pump
TL;DR: The async model is a contract. In .NET, async methods are expected to do little CPU work, spend most of their time awaiting input/output, and make long-running CPU work explicit. Lease renewal depends on that contract. If a handler hides blocking or CPU-heavy work inside an async method, the scheduler assumptions behind renewal can fall apart. The message pump depends on the broker API, but it also depends on the runtime’s execution model. After publishing the previous article...
When the handler outlives the lease
TL;DR: A visibility timeout is a lease. It tries to keep two consumers from working on the same queue message at the same time, but only for a limited period. If message handling takes longer than that period, the pump must renew the lease while business code continues to run. That sounds like a small addition until renewal needs scheduling, cancellation, shutdown behavior, mutable pop receipts, delete coordination, and a policy for what to do when renewal fails. The first version of the...
Message pumps fail in the transaction details
TL;DR: Reading bytes from a queue is the easy part of a message pump. Things get difficult when message handling writes to a database, sends more messages, fails halfway through, moves to another broker, or runs in a cloud service with different transaction semantics. A small infrastructure project can quietly turn into a platform commitment. None of this looked particularly scary when we started. It looked like a loop: read from a queue, deserialize a message, find the handler, and call it. We...
A message queue bought us time
TL;DR: A queue can remove temporal coupling between a front end and a back end, but something still has to read the messages and run the business code behind them. That something is the message pump. Processing one message at a time protects downstream systems but increases queue wait time. Fire-and-forget processing looks faster until concurrency runs away. In practice, the pump needs an explicit limit. The medical invoicing system already worked. That made the request harder, not easier. It...
Event Sourcing: compensation – the simple way out when things go wrong
In the fifth part of this event sourcing series, I’ll show you how we use compensation of events to handle failed commands and events that should never have happened. Sometimes, things go wrong – a command fails because the database is overloaded, there is a bug in the code for some edge case, the system is out of memory, the infrastructure misbehaves, etc. Or a user did something that should never have happened, like importing the wrong data set. When this happens, we want the...
Event Sourcing: You better Prevent long event streams
In the fourth part of my event sourcing series, we’ll take a look at why long event streams – streams with lots of events – are a problem and what options there are to deal with this problem. Why read models are not always enough to solve performance issues due to long event streams. And of course, I’ll discuss the involved trade-offs.
The Problem with Secondary Domain Events in Event Sourcing
We started using event sourcing over ten years ago. One of the hardest lessons was that there is a kind of events that is not obvious at first but have a big impact on your system design. I call this kind secondary domain events.
In this post, I’ll explain what secondary domain events are, and how they impact the design.
To test, or not to Test? Part 3 – Make it easier to recover from a defect
I wrote code without tests that ran in production without defects, and I wrote buggy code with TDD (Test Driven Development). Time to look back at 35 years of coding and when tests help, and when there is something better. And especially, what these better things are.
In this post, we look at what we can do to recover well even if a defect finds its way into production.