Microservices
Macro trends in the tech industry | April 2019
enterCafe .next(orderCoffee) .decisionBranch(COFFEE_WITH_MILK = boilMilk, BLACK_COFFEE = boilWater) .next(getSugarQuantity) .parallel(addCoffee, addSugar) .next(callCustomer) .next(makePayment) .next(checkPaymentStatus) .next(activateCafeMembership) .next(generateReceipt, dependsOn = checkPaymentStatus) .next(collectCoffee) .next(drinkCoffee) .next(leaveCafe)
Dependencies help the orchestrator determine when a task can be executed. We wouldn’t want a customer to collectCoffee before all the prerequisite tasks that it has a dependency on are performed. Dependencies can be interpreted either implicitly, based on the process definition or explicitly added.
1. Implicit Dependencies: callCustomer is dependent on addCoffee and addSugar and cannot be executed until they are complete. Such a dependency is implicitly inferred and does not require configuration because addSugar and addCoffee are System Tasks. The same is applicable for a Task after a Customer Task.(addCoffee, addSugar) .next(callCustomer)
makePayment .next(checkPaymentStatus) .next(activateCafeMembership) .next(generateReceipt, dependsOn = checkPaymentStatus)
orderCoffee .decisionBranch(COFFEE_WITH_MILK = boilMilk, BLACK_COFFEE = boilWater)
getSugarQuantity .parallel(addCoffee, addSugar)
class BoilMilk : AsyncStep() { fun execute() : Temperature { milkService.boil() } fun resume() : Temperature { this.execute() } }
configureCheckpoints(collectCoffee)
configureResetTasks(fromTask = collectCoffee, toTask = getSugarQuantity)
configureNonResettableTasks(activateCafeMembership)
{ "name": "coffee_ordering_process", "description": "Order coffee", "version": 1, "schemaVersion": 1, "tasks": [ { "name": "order_coffee", "taskReferenceName": "order_coffee_task", "inputParameters": { "contentId": "${workflow.input.coffee_type}" }, "type": "SIMPLE" } ] }
public class CoffeeOrderingProcess{ private final ActivityOptions options = new ActivityOptions.Builder().build(); private final CoffeeTasks tasks = Workflow .newActivityStub(CoffeeTasks.class, options); @WorkflowMethod public void orderCoffee(String customerName) { Saga.Options sagaOptions = new Saga.Options.Builder().build(); Saga saga = new Saga(sagaOptions); String orderCoffeeID = activities.orderCoffee(customerName); saga.addCompensation(activities::cancelCoffee, orderCoffeeId, customerName); } } public class CoffeeTasks { public String orderCoffee(String customerName) { System.out.println("orderCoffee for " + customerName); return UUID.randomUUID().toString(); } public String cancelCoffee(String customerName) { System.out.println("cancelCoffee for " + customerName); return UUID.randomUUID().toString(); } }
Disclaimer: The statements and opinions expressed in this article are those of the author(s) and do not necessarily reflect the positions of Thoughtworks.