@._.:
Generalnie mam mechanizm Sagi, to znaczy nasłuchuję na wszystkie eventy i we zwrotce może polecieć komenda, która trafia do command busa i tutaj właśnie może być kilka rozwiązań, które mi wypadły do głowy.
- Taka saga jest dummy, czyli zwraca bezposrednio komende. Zdaczylo się X, wykonaj komende Y. I ta komenda to będzie cała logika tej sagi. Czyli, mniej więcej robimy coś takiego Saga(Event) --> SagaAggregateComman(Event). Ta komenda to agregat ktory lapie eventy i on juz wie, gdzie co zrobic (np. do jakiej kolejki Rabbita wyslac itp)
- Podejście nieco inne, cala logika bezposrednio w tej sadze, czyli Saga(Event) -> logika w sadze -> Command(x), mówiąc po polsku, do sagi leci event, robimy jakąś robotę (tak jak wyżej, jakaś wysyłka do kolejki albo coś) i na koniec zwracamy komende (jeśli byśmy chcieli znowu na to zareagować)
Teraz pytanie brzmi, czy te podejścia są ok? Jeśli tak, to waszym zdaniem, które lepsze?
Moim zdaniem podejście drugie jest lepsze bo cały proces masz w jednym miejscu. Polecam sposób jak to robi MassTransit w C#
public class OrderProcessSaga : MassTransitStateMachine<OrderState>
{
private string OperationId { get; set; }
public OrderProcessSaga()
{
InstanceState(x => x.CurrentState);
Event(() => OrderCreated, x => x.CorrelateById(context => context.Message.OrderId));
Event(() => PaymentBegins, x => x.CorrelateById(context => context.Message.OrderId));
Event(() => PaymentFails, x => x.CorrelateById(context => context.Message.OrderId));
Event(() => PaymentSucceded, x => x.CorrelateById(context => context.Message.OrderId));
Event(() => OrderSubmited, x => x.CorrelateById(context => context.Message.OrderId));
Initially(
When(OrderCreated)
.Then(context =>
{
context.Instance.OrderId = context.Data.OrderId;
if (context.TryGetPayload(out ConsumeContext<IOrderCreated> consumeContext))
{
var opId = consumeContext.Headers.Get("operationId", "");
if (!string.IsNullOrEmpty(opId))
OperationId = opId;
}
})
.TransitionTo(OrderRegistered));
During(OrderRegistered,
When(PaymentBegins)
.Then(context=> { context.Instance.PaymentId = context.Data.PaymentId; })
.TransitionTo(PaymentProcessBegin),
When(PaymentFails)
.TransitionTo(PaymentProcessFails)
.Publish(context => new DeleteOrder{OrderId = context.Instance.OrderId})
.Finalize(),
When(PaymentSucceded)
.TransitionTo(PaymentProcessSucceded)
.Publish(context => new OrderSubmitted{OrderId = context.Instance.OrderId})
.Finalize());
}
public State OrderRegistered { get; private set; }
public State PaymentProcessBegin { get; private set; }
public State PaymentProcessFails { get; private set; }
public State PaymentProcessSucceded { get; private set; }
public State OrderSubmitted { get; private set; }
public Event<IOrderCreated> OrderCreated { get; private set; }
public Event<IPaymentProcessBegin> PaymentBegins { get; private set; }
public Event<IPaymentProcessFail> PaymentFails { get; private set; }
public Event<IPaymentProcessSucceded> PaymentSucceded { get; private set; }
public Event<IOrderSubmitted> OrderSubmited { get; private set; }
}
}