Skip to content

Routing Slips

Developing applications with a distributed, message-based architecture adds complexity to handling transactions, especially when all steps must either succeed together or fail completely. In traditional applications using an ACID database, transactions are managed through SQL, where partial operations are rolled back if the transaction fails. However, this approach doesn’t scale well when the transaction spans multiple services or databases. In modern microservices architectures, the reliance on a single ACID database has become increasingly rare.

MassTransit Routing Slips address this challenge by enabling distributed transactions with fault compensation, designed to scale across a network of services. It provides functionality previously handled by database transactions, but adapted for distributed systems. Routing Slips also integrate seamlessly with saga state machines, which add capabilities for transaction monitoring and recoverability.

MassTransit implements the Routing Slip pattern, leveraging durable messaging transports and the advanced saga features of MassTransit. Routing slips simplify the coordination of distributed transactions. When combined with a saga state machine, routing slips create a robust, recoverable, and maintainable approach to message processing across multiple services.

Beyond basic routing slip functionality, MassTransit also supports compensations, allowing activities to store execution data so that reversible operations can be undone. Compensation can be achieved either through traditional rollbacks or by performing offsetting operations. For instance, an activity that reserves a seat for a customer could release that reservation if compensation is triggered.

In MassTransit, a routing slip activity refers to a processing step that can be added to a routing slip.

A routing slip defines a sequence of routing slip activities that are combined to form an itinerary. As each activity completes, the routing slip is forwarded to the next activity in the itinerary. When all activities are completed, the routing slip is finalized, marking the transaction as complete.

One key advantage of using a routing slip is its flexibility — activities can vary for each transaction. Depending on factors like payment methods, billing/shipping address, or customer preferences, the routing slip builder can dynamically add activities. This is in contrast to the more rigid, predefined behavior of a state machine or sequential workflow, which are statically defined through code, a domain-specific language, or frameworks like Windows Workflow.

A routing slip contains an itinerary, variables, and activity/compensation logs. It is defined by a message contract, which the underlying routing slip components use to execute and compensate the transaction. The routing slip contract includes:

  • A unique tracking number for each routing slip
  • An itinerary that contains an ordered list of activities
  • An activity log that contains an ordered list of completed activities
  • A compensation log that contains data related to completed activities that can be compensated if the routing slip faults
  • A collection of variables that may be mapped to activity arguments
  • A collection of subscriptions for notifying consumers of routing slip events
  • A collection of exceptions that may have occurred during routing slip execution

Now that you understand the basics of routing slips, learn how to use them in your applications by following the guides.