Potentially long running (and complex) interactions with transactional characteristics.
func placeOrder(o Order) {
warehouse.ReserveItems(o.Items)
payment.ProcessPayment(o)
notifyBuyer(o, OrderPlaced)
saveOrder(o)
}
func placeOrder(o Order) {
reserved, err := warehouse.ReserveItems(o.Items)
if err != nil { // Warehouse service unavailable
// Retry?
}
if !reserved { // Business error requiring user intervention
notifySeller(o, OrderFailed)
notifyBuyer(o, OrderFailed)
return
}
// ...
}
Source: StackOverflow Blog
func placeOrder(o Order) {
warehouse.ReserveItems(o.Items)
payment.ProcessPayment(o)
notifyBuyer(o, OrderPlaced)
saveOrder(o)
}
Checkout the following repository:
https://github.com/sagikazarmark/cadence-intro-workshop
Follow the instructions in the readme.
make shell
func placeOrder(o Order) {
warehouse.ReserveItems(o.Items)
payment.ProcessPayment(o)
notifyBuyer(o, OrderPlaced)
saveOrder(o)
}
Write a test for Example 3.
Output value is based entirely on the input.
func add(a, b int) int {
return a + b
}
func add(a, b int) int {
// This is not deterministic
resp := http.Get(fmt.Sprintf("https://add.com/%d/%d", a, b))
return decodeBody(resp.Body)
}
time.Now
, time.Sleep
Use deterministic wrappers instead.
func Workflow(ctx workflow.Context, input Input) (Output, error) {
//...
encodedNumber := workflow.SideEffect(ctx, func(ctx workflow.Context) interface{} {
return rand.Intn(max)
})
//...
workflow.Sleep(ctx, 1*time.Second)
//...
}
Write a query handler (for your workflow from examples 3, 5) that returns the current number in the loop.
Add sleep at the beginning of the loop so you have time to query it using the CLI.
Rewrite the parity check (based on examples 3, 5, 8) as an activity (with retries and timeouts):
https://stackoverflow.blog/2020/11/23/the-macro-problem-with-microservices/