In modernen verteilten Systemen spielen Sagas eine zentrale Rolle, um Geschäftsprozesse über mehrere Microservices und Transaktionen hinweg zu orchestrieren. Eine der besten Möglichkeiten, diese Sagas zu verwalten, ist durch den Einsatz von State Machines. In der .NET-Welt bietet das MassTransit-Framework eine leistungsstarke Unterstützung für Sagas und State Machines.
In diesem Artikel werden wir die Grundlagen einer MassTransit Saga StateMachine untersuchen, wie sie implementiert wird und warum sie in verteilten Architekturen von Vorteil ist.
Was ist eine Saga?
Eine Saga ist ein Entwurfsmuster, das verwendet wird, um verteilte Transaktionen zu koordinieren. Da Microservices in einer verteilten Architektur normalerweise keine gemeinsamen Datenbanken verwenden, sind traditionelle Transaktionen über Systemgrenzen hinweg schwierig umzusetzen. Stattdessen verwendet eine Saga eine Reihe von Schritten oder Ereignissen, die zusammenarbeiten, um einen Geschäftsprozess abzuschließen. Sollte einer dieser Schritte fehlschlagen, führt die Saga Kompensationsmaßnahmen aus, um den Fehler zu beheben.
Was ist eine State Machine?
Eine State Machine (Zustandsmaschine) ist ein Modell der Berechnung, das den Zustand eines Systems und die Übergänge zwischen verschiedenen Zuständen darstellt. In einer State Machine basierten Saga werden diese Zustände und Übergänge durch Nachrichten oder Ereignisse gesteuert.
Eine State Machine verfolgt:
- Den aktuellen Zustand eines Geschäftsprozesses.
- Die möglichen Zustandsübergänge.
- Die Aktionen oder Ereignisse, die jeden Übergang auslösen.
MassTransit und State Machines
MassTransit ist ein populäres Open-Source-Bibliothek für .NET, die für Messaging und verteilte Anwendungen entwickelt wurde. Es bietet die Implementierung von Sagas und unterstützt die Erstellung von State Machines, um komplexe Geschäftsprozesse zu verwalten.
Mit MassTransit können Sie:
- Sagas implementieren, die sich über mehrere Nachrichten hinweg erstrecken.
- Zustandsübergänge basierend auf empfangenen Nachrichten definieren.
- Den Status und Verlauf der Saga speichern und überwachen.
Implementierung einer Saga StateMachine in MassTransit
- Definieren der Saga StateMachine Eine MassTransit Saga StateMachine wird durch das Erstellen einer Klasse definiert, die von der MassTransitStateMachine-Klasse erbt. Dies ermöglicht es Ihnen, den Zustand, die Übergänge und die Reaktionen auf Ereignisse zu definieren.
public class OrderState : SagaStateMachineInstance
{
public Guid CorrelationId { get; set; }
public string CurrentState { get; set; }
public Guid OrderId { get; set; }
public DateTime Created { get; set; }
}
public class OrderStateMachine : MassTransitStateMachine<OrderState>
{
public State Submitted { get; private set; }
public State Completed { get; private set; }
public Event<SubmitOrder> SubmitOrderEvent { get; private set; }
public Event<CompleteOrder> CompleteOrderEvent { get; private set; }
public OrderStateMachine()
{
InstanceState(x => x.CurrentState);
Event(() => SubmitOrderEvent, x => x.CorrelateById(m => m.Message.OrderId));
Event(() => CompleteOrderEvent, x => x.CorrelateById(m => m.Message.OrderId));
Initially(
When(SubmitOrderEvent)
.Then(context =>
{
context.Instance.OrderId = context.Data.OrderId;
context.Instance.Created = DateTime.Now;
})
.TransitionTo(Submitted));
During(Submitted,
When(CompleteOrderEvent)
.TransitionTo(Completed));
}
}
- Implementierung der Nachrichten (Events) Die Ereignisse oder Nachrichten, die durch das System geschickt werden, müssen als Klassen definiert werden. Diese Nachrichten enthalten in der Regel die notwendigen Daten für die Saga, um Zustandsübergänge zu steuern.
public class SubmitOrder
{
public Guid OrderId { get; set; }
}
public class CompleteOrder
{
public Guid OrderId { get; set; }
}
- Saga Repository Konfiguration Um den Zustand der Saga über längere Zeiträume hinweg zu speichern, benötigen wir ein Repository, das die Saga-Instanzen persistiert. MassTransit unterstützt verschiedene Persistenztechnologien wie Entity Framework, MongoDB oder InMemory.
Ein Beispiel mit Entity Framework:
public class OrderStateMap : SagaClassMap<OrderState>
{
protected override void Configure(EntityTypeBuilder<OrderState> entity, ModelBuilder model)
{
entity.Property(x => x.CurrentState);
entity.Property(x => x.OrderId);
entity.Property(x => x.Created);
}
}
services.AddMassTransit(x =>
{
x.AddSagaStateMachine<OrderStateMachine, OrderState>()
.EntityFrameworkRepository(r =>
{
r.ConcurrencyMode = ConcurrencyMode.Optimistic;
r.AddDbContext<DbContext, SagaDbContext>((provider, optionsBuilder) =>
{
optionsBuilder.UseSqlServer("your-connection-string");
});
});
});
- MassTransit-Konfiguration in ASP.NET Core Schließlich müssen Sie MassTransit und die Saga in Ihrer ASP.NET Core-Anwendung konfigurieren:
public void ConfigureServices(IServiceCollection services)
{
services.AddMassTransit(x =>
{
x.UsingRabbitMq((context, cfg) =>
{
cfg.Host("rabbitmq://localhost");
cfg.ConfigureEndpoints(context);
});
});
}
Fazit
Die Kombination aus Sagas und State Machines in MassTransit ermöglicht es Entwicklern, komplexe verteilte Geschäftsprozesse auf elegante Weise zu orchestrieren. Die State Machine verfolgt den Zustand der Saga und ermöglicht es, auf eingehende Ereignisse zu reagieren, um den Prozess voranzutreiben oder zu kompensieren, wenn Fehler auftreten.
Die Verwendung von MassTransit als Messaging-Plattform macht diese Aufgaben relativ unkompliziert und bietet gleichzeitig eine robuste Unterstützung für verschiedene Persistenzmechanismen, wodurch die Implementierung einer zuverlässigen, verteilten Transaktionsverarbeitung erleichtert wird.