This document discusses building autonomous microservices and provides assignments to practice designing services that are autonomous and event-driven. It introduces a simplified e-commerce domain with Catalog, Purchase, Sales, and Stock services and assigns tasks to modify the services to be more autonomous by subscribing to each other's events, updating internal state, and responding without direct communication. The assignments introduce concepts like process managers, event conversion, and using the reservation pattern to avoid concurrency issues. Questions are also provided throughout to help think through architectural challenges.
4. About the domain
We have a much simplified warehousing domain with
several services:
1. Catalog: Managing products in a catalog.
2. Purchasing: Receiving products that were previously
purchased from a supplier.
3. Sales: selling to a customer products that we have in
stock.
5. What are we doing here?
Building autonomous services
24. Solving the query issue
1. Services publish their events.
2. Other services subscribe to these events and update their
own state accordingly.
3. They can build up any projection they like. This gives
them the answers they need, without even asking.
32. Questions
Since you may have created a product before you started
publishing events about it, your database may contain
products, which are not in the stream. Hence, they are not
stored as local products in the *Purchase* context. What
would be needed to fix these inconsistencies? Think of/
discuss several strategies.
33. Questions
What happens if you have a bug in your consumer and it
doesn't process an incoming event correctly? Take a look at
the code and comments of `Stream::consume()` and find out
what its built-in mechanism is to counter this situation.
What does this mean for the implementation of the
consumer?
36. Process manager
• Consumes every message (event) from the stream only
once
• Responds with any of the following:
• Publishing a command
• Producing a new event
• Updating the status of a long-running process
39. Questions
Events potentially increase coupling between services. An
event exposes details about the internal domain model of a
service. When consuming events, services gather
knowledge about each other's internals. This can lead to
something known as a "distributed monolith". There may be
runtime autonomy, but there will be lots of violations of
D.R.Y. (the *knowledge* aspect of it). Come up with a way to
prevent this.
40. Questions
*Stock* currently doesn't store the names of the products,
would it be better if it would? Think of some reasons for or
against it.
42. Contexts
• Transition of meaning: in one context "goods received", in
the other context "stock increased".
• Simplification of the message (same example), but also: "user
added" as a summary of "user created", "user activated",
"email confirmed", etc.
43. Upon receiving an event...
• Produce a new event and add it to the stream.
• This is a side-effect (i.e. it has effects noticeable on the
outside of the service).
• A "projector consumer" can rebuild its projection again and
again, because it's internal to the service.
46. Questions
Couldn't we just use a "stock level changed" event?
What about "stock level increased/decreased" events with a
"current stock level" value?
48. Questions
Should we create a purchase order for the entire quantity of
the sales order, or just the difference between the ordered
quantity and the current stock level?
49. Questions
What have we done?! We have created a direct, runtime
dependency between *Sales* and *Purchase*... Not very
smart, since the request for making a sales order might fail,
even though the reason for this failure is a problem in
*Purchase*. Can you think of a solution for the lack in
autonomy?
50. Questions
Consider the following situation: when we check for the
current stock level of a product, immediately after that the
product gets delivered to someone else. So when we try to
deliver our sales order, it won't be possible anymore (and
we should have added it to the purchase order after all!).
What could we do about this?
52. The Reservation Pattern
• In a system with concurrency, there's always the chance
you're looking at stale data.
• If you sell x items to a customer, they could be sold at the
same time to another customer.
• So: you first need to make a reservation.
53. Stock reservation
• New sales order? Make a stock reservation.
• When it's okay, commit and deliver the order.
• When it's not okay, respond to it: make a purchase order.