I am learning about event drive microservices. I think I understood the basics but can't wrap my head around a few things. This question is theoretically. I am not looking for answers like "use a hosted shopping cart or stuff" The services:
- Catalogue service: show product (sort, filter ect.)
- Shopping cart: a shopping cart for anonymous users (add items, remove items, show shopping cart with items)
- Pricing service: calculate price for item (depending on location and so on)
- Payment service: setup payment provider keep track on payment provider callbacks (example: setup stripe session, react to web hooks)
So lets image the "simple situation": User added items to the cart and wants to checkout. This shows a screen with: summary of products and their prices, button to continue with the payment provider. user clicks on the pay button. so the payment service has to have information from the shopping cart, the pricing service and maybe even from the product service like the product category to list in the discretion in stripe/paypal. A for the user/ui the button click should feel synchronous.
So how does the payment service have all this information: When the user clicks on the button. I shouldn't synchronous collect the information from all the services. at which point do flow the information here?
maybe I got something wrong but to get to this point in the checkout I imagine this things happen with a few ideas
- Catalogue Service to Shopping Cart Service.
- Event:
itemAddedToCartEvent - Flow: When a user adds an item to their cart, the Catalogue Service emits itemAddedToCartEvent, which includes essential details like
uuidandproductName. - Shopping Cart Service's Role: Picks up this event, stores the item details for display in the UI, and prepares for the next step (checkout).
- Pricing Service Interaction
- Challenge: The Shopping Cart needs to display item prices. Potential Solution:
- Option A: Upon
itemAddedToCartEvent, the Cart Service sends a request to the Pricing Service to get the price for the item. The response is then stored within the Cart Service. (bad async not event based! - not want that) - Option B: The Pricing Service listens for
itemAddedToCartEventand emits anitemPriceCalculatedEventwith the price. The Cart Service listens for this event and updates the cart's price details accordingly. is it okay to have a flow like this? how do we propagate this to the ui (but isn't an anti patter I read: passive aggressive events but I want a reply)
- Preparing for Checkout
- Flow: When the user is ready to checkout, the Shopping Cart Service already has the item details and prices. It can generate a summary view of the cart for the user to review before proceeding to payment.
- Initiating Payment
- Event:
cartCheckedOutEvent - Flow:
When the user clicks the pay button, this event is emitted.
The Payment Service listens for
cartCheckedOutEvent. - Challenge: The Payment Service needs information from the Cart (items and their quantities), Pricing Service (prices), and potentially the Catalogue Service (product categories) and need to give ui feedback
- Aggregating Information for Payment
Options for the Payment Service to Gather Data:
Direct Requests: It could make direct, synchronous requests to the Cart and Pricing Services, but this approach may not be efficient or scalable.
Event-Driven Approach: the Payment Service has been listening to the flow of events (like item additions and price calculations) and maintaining a lightweight, transient representation of necessary data for each active cart. This way, when
cartCheckedOutEventoccurs, it already has most of the needed information. fetch: ThecartCheckedOutEventcan include a reference to the cart ID, which the Payment Service uses to fetch the latest cart details. (bad again or is it fine this time).
- Setting Up Payment Session The Payment Service, now with all required information, interacts with the payment provider (like Stripe or PayPal) to set up a payment session and handles the provider's callbacks.
My recommendations so you can assess and take your own decisions. I don't know all the details and some of them could be related to the organisation structure itself.
You are suspicious about Crossing boundaries and you are right to do so. Crossing boundaries have its penalties in terms of development costs, complexity, so you should try to minimise it if possible. Don't try to create the perfect theoretical solution in your head. It is better to start simple even at the cost of purity, and go to detail later when the experience and knowledge indicates you.
I agree with the interactions between the Product Catalog, Pricing and Shopping cart. I would start increasing the Shopping cart functionality so it has a central role. It covers everything for which you think you need all the shopping cart information in the payment service. Then when the payment is triggered with all the Payment details it will need to listen to the payTotalShoppingCart event with just the total amount. Payment is agnostic of the what has been bought.
It is difficult to answer, as we could be discussing for a while in detail. In general I prefer to avoid cross boundaries at the expense to do a small controllable monolith. Then divide it in the future if a need leading a new design reveals it.