Some confusion about CQRS in Saving/Post callback


Hello, thank you very much for your tutorial about using CQRS with micro services! I am a big fan of your tutorial and after digging more into it, I become confused with a few concept around CQRS, could you please give me any hint or suggestion on those?

  1. Usage of your Command and Event message type in the project. It looks like both of them are very similar, no return object(immutable), both can be published and subscribe through RabbitMQ, I noticed that command was sent through dispatcher or RabbitMQ while event was only sent through RabbitMQ, but I mean seems like Command could replace the Event…, so what’s the core difference between those two and when should we use one over another?
  2. This is something I’m very interested, I assume that when perform WRITE operation we should use Command or Event, while when perform READ operation, we should use Query. However, sometimes, after we perform a WRITE operation, let’s say for example:
    • CreateDiscount from web application, with the usage of event DiscountCreated in your case as a callback and handled in EventHandler, yes we can sent email in event handler but we cannot return any information back to Client side like a message Your Discount Created Successfully or Something went wrong after retrying failed, our api gateway will always return nothing but a Accept() signal, so how could we or the client side know that my last WRITE operation performed successfully or not? I’ve seen you’re using the Operation Service and SignalR to catch the real-time response, very nice! But would it be redundant that SignalR had to subscribe message from Operation? I feel the Operation works like a middleware to transit the success or error response from internal API command handler, could we get rid of the Operation Service and let Discount Service talk directly to SignalR?
  3. The only handler that can return some data is Query Handler which I’ve seen you used it as performing READ operation, and it is unable to publish or subscribe through rabbitMQ, I guess it’s because for READ operation we need immediate action, correct? But why we need to do things like first dispatch then resolve by handler within same internal service, why not just do everything on API Controller level? I guess it may because of CQRS related principle, but not sure if that’s the correct way for doing every READ operation in this way or in what scenario we need to do like local dispatch for READ…would there be any latency by doing that?

Thank you again for your generous help and knowledge share! I really appreciate everything a lot!

  1. It’s semantics - for the message broker, everything is a message, however, for your application, there’s a significant difference between a command (do something - it’s an order) and an event (something has happened, maybe you want to do something based on that fact).

  2. Wet talked about it in 7th episode - returning the state of async operations can be tricky, and usually, you need to provide some additional services to take care of tracking the ongoing requests and sending e.g. push notifications to the end-users about what’s happening in the system.

  3. Yes, you should probably never query data by using the async approach (meaning, you should not send a query to the message broker). Speaking of CQRS - you can use in-memory dispatcher and query handlers if you want to follow this approach (IMO it’s a cleaner solution, and every handler represents a single use case), yet you don’t need to do it at all :slight_smile:. The overall result will be the same, and there should be any differences in performance or overall latency.