Basics
One way or another, Wolverine is all about messages within your system or between systems (Wolverine considers HTTP to just be a different flavor of message 😃). Staying inside a single Wolverine system, a message is typically just a .NET class or struct or C#/F# record. A message generally represents either a "command" that should trigger an operation or an "event" that just lets another part of your system know that something happened. Just know that as far as Wolverine is concerned, those are roles and unlike some other messaging frameworks, will have no impact whatsoever on Wolverine's handling or implementation.
Here's a couple simple samples:
// A "command" message
public record DebitAccount(long AccountId, decimal Amount);
// An "event" message
public record AccountOverdrawn(long AccountId);
The next concept in Wolverine is a message handler, which is just a method that "knows" how to process an incoming message. Here's an extremely simple example:
public static class DebitAccountHandler
{
public static void Handle(DebitAccount account)
{
Console.WriteLine($"I'm supposed to debit {account.Amount} from account {account.AccountId}");
}
}
Wolverine can act as a completely local mediator tool that allows your code to invoke the handler for a message at any time without having to know anything about exactly how that message is processed with this usage:
public async Task invoke_debit_account(IMessageBus bus)
{
// Debit $250 from the account #2222
await bus.InvokeAsync(new DebitAccount(2222, 250));
}
There's certainly some value in Wolverine just being a command bus running inside of a single process, Wolverine also allows you to both publish and process messages received through external infrastructure like Rabbit MQ or Pulsar.
To put this into perspective, here's how a Wolverine application could be connected to the outside world:
TIP
The diagram above should just say "Message Handler" as Wolverine makes no structural differentiation between commands or events, but Jeremy is being too lazy to fix the diagram.
Terminology
- Message -- Typically just a .NET class or C# record that can be easily serialized. See messages and serialization for more information
- Envelope -- Wolverine's Envelope Wrapper model that wraps the raw messages with metadata
- Message Handler -- A method or function that "knows" how to process an incoming message. See Message Handlers for more information
- Transport -- This refers to the support within Wolverine for external messaging infrastructure tools like Rabbit MQ, Amazon SQS, Azure Service Bus, or Wolverine's built in TCP transport
- Endpoint -- The configuration for a Wolverine connection to some sort of external resource like a Rabbit MQ exchange or an Amazon SQS queue. The Async API specification refers to this as a channel, and Wolverine may very well change its nomenclature in the future to be consistent with Async API.
- Sending Agent -- You won't use this directly in your own code, but Wolverine's internal adapters to publish outgoing messages to transport endpoints
- Listening Agent -- Again, an internal detail of Wolverine that receives messages from external transport endpoints, and mediates between the transports and executing the message handlers
- Node -- Not to be confused with Node.js or Kubernetes "Node", in this documentation, "node" is just meant to be a running instance of your Wolverine application within an application cluster of any sort
- Agent -- Wolverine has a concept of stateful software "agents" that run on a single node, with Wolverine controlling the distribution of the agents. This is mostly used behind the scenes, but just know that it exists
- Message Store -- Database storage for Wolverine's inbox/outbox persistent messaging. A durable message store is necessary for Wolverine to support leader election, node/agent assignments, durable scheduled messaging in most cases, and its transactional inbox/outbox support
- Durability Agent -- An internal subsystem in Wolverine that runs in a background service to interact with the message store for Wolverine's transactional inbox/outbox functionality