0

Am new to Microservices and CQRS event handling. I am trying to understand with one simple task. In this task I have three REST external services to handle one transaction/request(Service). The three services are

step1: customer create.

step2: create business for customer

step3: Create Address for business.

I want to implement SAGA for these events with InMemorySagaRepository and saga manager.

Where exactly I have to initiate the SagaManager with repository, Is it in RestController or in CommandHandler ?

Can you please help me in understanding sagas flow ?

Thanks in Advance.

ArK
  • 20,698
  • 67
  • 109
  • 136
  • Welcome to Stack Overflow. You can improve your question. Please read [How to Ask](http://stackoverflow.com/help/how-to-ask) including the link "How to ask questions the smart way." – zhon Aug 19 '16 at 03:15
  • We use event sourcing and CQRS at work. We've found that 'saga' means different things for different people. So I just want a clarification: What do *you* mean by saga? A link to where you read up on it would be of much help just so we know what you are asking about. – qwelyt Aug 19 '16 at 06:19

3 Answers3

4

Half a year later, and I'm making an edit as I've now taken a course held by Greg Young called Greg Young's CQRS, Domain Events, Event Sourcing and how to apply DDD I really recommend it to anyone thinking about CQRS. Help A LOT to understand what things actually are


Original anwser

In our product we use Sagas as something that reacts to events. This means that our sagas are really just Subscribers to a specific Event. The saga then holds some logic as to whether it should do something or not. If the saga finds that an action should be taken, it creates a Command which it puts on the CommandBus. This means that Sagas are just 'reactors' and use the same path in as a user would (skipping the APIs etc).

But what a Saga really is, and what it should do, differs from the one talking about them to the other. (Disclaimer: This is how I read these posts, they might actually all say the same thing, but in a way to fluffy way for me [+my team] to see that)

http://blog.jonathanoliver.com/cqrs-sagas-with-event-sourcing-part-i-of-ii/ for example, raises the point that Sagas should not contain 'business logic' (anything that contains 'if' is business logic according to the post).

https://msdn.microsoft.com/en-us/library/jj591569.aspx Talks about Sagas as 'Process managers' which coordinate things between different Aggregates (remember that Aggregate1 can't talk to Aggregat2 directly, so a 'Process manager' is required to orchestrate the communication). To put it simply: Event -> Saga -> Command -> Event -> Saga... To reach the final destination.

https://lostechies.com/jimmybogard/2013/03/21/saga-implementation-patterns-variations/ Talks about two different patterns of what a Saga is. One is 'Publish-gatherer' which basically coordinates what should happen based on a Command. The other is 'Reporter', which just reports the status of things to where they need to go. It doesn't coordinate things, it just reports whatever it needs to report.

http://kellabyte.com/2012/05/30/clarifying-the-saga-pattern/ Has a write-up of what the Saga-pattern 'is'. The claim is that Sagas should/could compensate for different workflows that break.

http://cqrs.nu/Faq/sagas Has a very short description on what Sagas are and basically says 'They are state machines that lets aggregates react to other aggregates'.

So, given that, what is it you actually want the Saga to do? Should it coordinate everything? Or should it just react and not care what the Aggregates do?


My edited part

So, after taking the course on CQRS and talking with Greg about this, I've come to the conclusion that there is quite a lot of confusion out there on the web.

Lets start with just the concept 'Saga'. A Saga has actually nothing to do with CQRS. It's not a concept of it. 'Saga' a form of a two-phase-commit, only it's optimised for success rather than fail ( https://en.wikipedia.org/wiki/Compensating_transaction )

Now, what most people mean when they talk CQRS and say "Saga" is "Process Manager". And process managers are quite complicated it seems (Greg has a whole other course for just Process Managers). Basically what they do is the manage the whole process of something (as the name suggests). The link to Microsoft is pretty much what it's all about.

To answer the question:

Where exactly I have to initiate the SagaManager with repository, Is it in RestController or in CommandHandler ?

Outside of them both. A Process Manager is it's own thing. It spans aggregates and repositories. Conceptually it might be better to look at it as a user doing all the things you want the PM do to, just that you program the users interaction and tell it what to listen for.

Disclaimer: I do not work for Greg, or anyone that stands to gain on my promotion for taking his courses. It's just that I learned a lot from it, so I recommend it just like I would recommend reading Eric Evans book on DDD.

qwelyt
  • 776
  • 9
  • 23
  • Thank you for your quick response. My requirement is to coordinate services/events. – user1386039 Aug 22 '16 at 16:39
  • @user1386039 I take it you mean coordinate as in it will be intricately involved in how the aggregates behave. As the other option ('reactor') don't really care about how the aggregates are. Do you want the saga to prevent Events from happening? This means doing it all in the Command layer, or having a Saga that somehow prevents Events from being published. – qwelyt Aug 23 '16 at 05:42
  • @ShawnMclean The one done via SkillsMatter https://skillsmatter.com/courses/345-greg-youngs-cqrs-domain-events-event-sourcing-and-how-to-apply-ddd – qwelyt Jul 05 '17 at 07:57
1

In my application i've build Saga process manager using this MSDN documentation, my Saga is implemented in Application Service layer, it listens Events of Sales, Warehouse & Billing bounded contexts and on event occurrence sends Commands via Service Bus.

Simple example, hope it helps you to analyze how to build your saga (I am registering saga as handler in Composition Root) ;):

SAGA:

    public class SalesSaga : Saga<SalesSagaData>,
    ISagaStartedBy<OrderPlaced>,
    IMessageHandler<StockReserved>,
    IMessageHandler<PaymentAccepted>
{
    private readonly ISagaPersister storage;
    private readonly IBus bus;

    public SalesSaga(ISagaPersister storage, IBus bus)
    {
        this.storage = storage;
        this.bus = bus;
    }

    public void Handle(OrderPlaced message)
    {
        // Send ReserveStock command
        // Save SalesSagaData
    }

    public void Handle(StockReserved message)
    {
        // Restore & Update SalesSagaData
        // Send BillCustomer command
        // Save SalesSagaData
    }
    public void Handle(PaymentAccepted message)
    {
        // Restore & Update SalesSagaData
        // Send AcceptOrder command
        // Complete Saga (Dispose SalesSagaData)
    }
}

InMemorySagaPersister: (as SalesSagaDataID i am using OrderID its unique across whole process)

    public sealed class InMemorySagaPersister : ISagaPersister
{
    private static readonly Lazy<InMemorySagaPersister> instance = new Lazy<InMemorySagaPersister>(() => new InMemorySagaPersister());

    private InMemorySagaPersister()
    {
    }

    public static InMemorySagaPersister Instance
    {
        get
        {
            return instance.Value;
        }
    }

    ConcurrentDictionary<int, ISagaData> data = new ConcurrentDictionary<int, ISagaData>();

    public T GetByID<T>(int id) where T : ISagaData
    {
        T value;
        var tData = new ConcurrentDictionary<int, T>(data.Where(c => c.Value.GetType() == typeof(T))
            .Select(c => new KeyValuePair<int, T>(c.Key, (T)c.Value))
            .ToArray());

        tData.TryGetValue(id, out value);
        return value;
    }

    public bool Save(ISagaData sagaData)
    {
        bool result;

        ISagaData existingValue;
        data.TryGetValue(sagaData.Id, out existingValue);
        if (existingValue == null)
            result = data.TryAdd(sagaData.Id, sagaData);
        else
            result = data.TryUpdate(sagaData.Id, sagaData, existingValue);

        return result;
    }

    public bool Complete(ISagaData sagaData)
    {
        ISagaData existingValue;
        return data.TryRemove(sagaData.Id, out existingValue);
    }
}
QuietNaN
  • 371
  • 1
  • 14
0

One approach might be to have some sort of starting command that starts the Saga. In this scenario it would be configured in your composition root to listen to a certain command type. Once a command has been received in your message dispatcher (or whatever middleware messaging stuff you have) it would look for any Sagas that have been registered to be started by the command. You would then create the Saga and pass it the command. It could then react to other commands and events as they happen.

In your scenario I would suggest your Saga is a type of command handler so the initiation of it would be upon receiving a command

tomliversidge
  • 2,339
  • 1
  • 15
  • 15
  • Thank you for your quick response. My main service is invoking three other services. If am not wrong I have to initiate my saga in main service. – user1386039 Aug 22 '16 at 16:41