Skip to main content

Particular Software Blog

Latest articles

  • Multiple endpoint hosting

    Multiple cats representing messaging endpoints, all chasing envelopes that represent messages

    Throughout the history of NServiceBus, there has been a fairly standard practice:

    1 endpoint == 1 queue == 1 process

    The endpoint owned everything within the process boundary and used assembly scanning to find and wire up all the things that make up that endpoint. While you could use “satellites”, you really couldn’t put more than one full endpoint inside a process boundary.

    But… what if it didn’t have to be that way?

    Read more

    1. …because there are a low number of endpoints that happen to be scaled out to multiple tenants, using the same code but deployed separately due to different configuration and scalability needs.

    2. …and dare I say, more fun?

    3. This is because source generators do not perform well when driven off implemented interfaces, so Microsoft recommends you Never Do That®. Scans using an attribute are the fastest and most optimized code path, which is important because a source generator can technically run every time you press a key in your IDE.

    4. Or even most?

  • Redesigning the NServiceBus pipeline yet again: The nerd sniping of Daniel Marbach

    Two fish, one representing a trim-capable pipeline, the other representing an impossible performance improvement, both eyeing a fish hook lowered into the water

    Daniel and I 1 have worked on improvements to the NServiceBus pipeline multiple times before: a 10x speed-up in 2017, and another 5x improvement in 2022. We thought we were all done with that.

    So, quite unexpectedly, this is the story of how I accidentally nerd sniped Daniel into redesigning the NServiceBus pipeline yet again.

    One little comment from me, and Daniel made the pipeline start 330x faster and run 25-29% faster on the success path, while still producing zero allocations along that path.

    Do I feel a little bad about it? Yes. Will I get over it? Also probably yes.

    Read more

    1. David, your author, and Daniel's nemesis. Ok, not really. Daniel and I are great buds, but I digress…

    2. And given that, it logically follows that one of the first things to get trimmed away would be the compiler code itself.

    3. If you analyze it another way, there were 5 years between the first two performance enhancements, and then 4 years between the previous one and this one. Assuming a linear decrease in time between pipeline improvements, can we expect another groundbreaking performance enhancement in just 3 years? You'll have to check back with us in 2029 to find out.

    4. Andrew Lock does a fantastic job explaining new .NET features like this one, but an even better job at highlighting why it matters. If you don't follow his posts, you should!

    5. If you're interested, our code is open source, you know…

    6. Our first iteration of prewired invokers used exactly that: 130 lines of hardcoded switch-case factory code that mapped each context type to its corresponding InvokerNode<TIn, TOut type.

    7. Daniel had his revenge on me during the editing of this post. After I recalled the XKCD origin of the term "nerd sniping" I was drawn in by the "infinite grid of one-ohm resistors" (my original degree was in Electrical Engineering) sending me far down a rabbit hole that included a trip to Physics Stack Exchange and, far too many minutes later, a realization that I no longer remember enough calculus to understand the math going on there.

  • Preparing NServiceBus for trimming and AOT

    Trimming a tree

    Trimming a tree blindfolded is probably not the best idea in the world. The best-case scenario is “at least the tree didn’t die.” The worst-case scenario is a trip to the emergency room. 1

    The .NET ecosystem is getting into the tree-trimming business (in a manner of speaking), and we’re starting to make changes to NServiceBus to ensure you won’t be caught trimming your apps with a blindfold on.

    Trimming and ahead-of-time compilation (AOT) reward code that the compiler can see. That changes some of the design assumptions for a framework like NServiceBus, which until now has relied on runtime discovery to maintain a productive developer experience.

    Read more

    1. Those scissors are sharp!

    2. This is because source generators do not perform well when driven off implemented interfaces, so Microsoft recommends you Never Do That®. Scans using an attribute are the fastest and most optimized code path, which is important because a source generator can technically run every time you press a key in your IDE.

    3. To check a package for yourself, navigate to the NuGet package page, click the Open in NuGet Package Explorer link such as this one for Npgsql, open the lib folder, then (generally) the latest net*.0 directory, and then click on the assembly DLL. Now look below for any AssemblyMetadata values. A package is trimmable if the key IsTrimmable has value True, and is AOT-compatible if IsAotCompatible has value True.

    4. That's right, if the source generator generates code that refers to your handler type, it will no longer be flagged as having no references!

  • Our new Small Business Program

    Sketch image showing gradual discount levels
    Update 2026-03-31: Particular has contributed the SmallBusinessProgram repository to the Use What Works community organization. Update 2026-01-15: Following Dylan Beattie’s video about licensing models in the .NET ecosystem, and the discussions it triggered in the community, we have decided to open-source our Small Business Program. We’re making it available under the CC-BY license so that everybody can reuse, mix, and modify it without worry of copyright infringement. We hope this will make it that extra bit easier for others to… Read more
  • AWS Enhancements

    Cartoon image conveying building construction around AWS

    Check out the latest enhancements to NServiceBus support for AWS. All of these updates aim to give you more control, fewer surprises, and a smoother experience when building distributed message-based systems on AWS.

    Read more

    1. 30 seconds by default

    2. Check out our blog post Infrastructure soup or our pipeline behavior documentation for more info.

  • Resistance is futile...unless you have ServicePulse

    Screen on the Star Trek Enterprise providing an imagined futuristic view of ServicePulse
    ServicePulse helps you recover from failures

    We are the Borg. Your messages have failed and will be assimilated. Resistance is futile.

    Distributed systems are a lot like Star Trek’s infamous Borg Collective: massively parallel, highly interconnected, and sometimes, drones services go down or are inaccessible. After all, even with a galaxy-class architecture, things sometimes go wrong. Messages can fail due to transient errors, unexpected exceptions, or configuration hiccups. However, well-designed distributed systems take a stronger cue from the Borg; they are built to be resilient. But how? Let’s explore a more peaceful quadrant of the galaxy to illustrate how this works.

    Read more

    1. In the 24th century, this would probably be NServiceBus version 168?

    2. Do you think that's still a thing in the 24th century?

  • It's a Trap! The Two Generals' Problem

    In distributed systems, coordination is hard—really hard—especially when both parties depend on mutual confirmation to proceed, but there’s no guarantee their messages will arrive. This classic dilemma is known as the Two Generals’ Problem. Like most problems in computer science, it’s easier to understand when explained with lasers, spaceships, and sarcastic smugglers.

    Let’s set the stage: It’s Return of the Jedi and the second Death Star looms large over the forest moon of Endor. The Rebel Alliance’s plan hinges on a synchronized attack — Han Solo leads the ground team to destroy the shield generator, while Lando Calrissian leads the space fleet to attack the Death Star itself.

    For the mission to succeed, both parties must execute their part of the plan. If either side decides to abort, the other must as well, or it will be a disaster.

    And here’s the twist: Han and Lando can only communicate through spotty, insecure rebel comms. Sound familiar?

    Read more
  • Achieving lean controllers: Incremental refactoring with Transactional Session

    It doesn’t matter if you’re developing using MVC, WebAPI, or Razor pages—you want your controller code to be nice and lean. The more bloated that code is, the more coupling you have, and the closer you are to an unmanageable big ball of mud.

    You probably already know that, but I’d bet not all of your controller code is as lean as you’d like it to be. Is it?

    So that leaves the question… How do we get there?

    Read more

    1. In a good way. Boring code is reliable code!

    2. It's almost always the tables!

    3. Implementations exist for SQL databases, Cosmos DB, Azure Tables, DynamoDB, MongoDB, and RavenDB.

  • Managing success and growing pains

    Every software system evolves through different stages of complexity. They start simple—attempting to solve a problem that might not yet be well-defined. As they grow, problems become more well-defined, and then they grow some more. Just like with lanky teenagers, this growth can sometimes cause growing pains. A skilled architect knows how to watch for the signs of these growing pains and how to apply more robust architectural patterns to ensure the system can continue to grow and flourish.

    This post is the story of the growing pains experienced by our friends at VECOZO, a system integrator that ensures safe communication between numerous healthcare-related companies. They knew it would be irresponsible to design every piece of software to handle massive scale, even if it only had a few users. So, when the architects started to see telltale signs, they knew it was time to deploy more robust architectural patterns.

    As you read on, maybe you’ll find that some of the challenges they faced sound familiar…

    Read more
  • What they don't tell you about migrating a message-based system to the cloud

    Migrating a message-based system from on-premises to the cloud is a colossal undertaking. If you search for “how to migrate to the cloud”, there are reams of articles that encourage you to understand your system, evaluate cloud providers, choose the right messaging service, and manage security and compliance.

    Curiously, what’s often missing from the discussion is details, like how to handle all the other on-prem systems that integrate with your system, both upstream and downstream, that can’t be upgraded at the same time. This gets even more tricky when those integrations are over on-prem-only technologies, like MSMQ, that don’t integrate out-of-the-box with cloud alternatives like Azure Service Bus or Amazon SQS. It’s as if they’re saying, “Have you documented your system? Great! Have you chosen a cloud provider? Awesome! Do you have all the services in place? Wonderful! Now go rewrite all your code… we’ll wait…are you done yet?..What are you looking at me for? I’ve already told you to plan carefully, I can’t do EVERYTHING for you”

    Read more