Without EA Async (2)
slisaasquatch opened this issue · comments
public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost) {
return bank.decrement(cost)
.thenCompose(decResult -> {
if (decResult) return completedFuture(false);
return completedFuture(null) // defer error
.thenCompose(_void -> inventory.giveItem(itemTypeId))
.handle((giveResult, t) -> {
if (t == null) return completedFuture(true);
return bank.refund(cost)
.<Boolean>thenApply(refundResult -> {
throw new RuntimeException(t);
});
})
.thenCompose(Function.identity());
});
}
I'm not saying it's prettier than the example, but I don't think this is ugly.
Definitely more difficult to follow the flow though, which is the main issue with promises/futures.
I saw this in the readme and couldn't help but think how it would be done.
I saw there are already 2 issues so i'm not making a new one, but it's an interesting example.
two problems make it difficult.
- The bank decrement has no error handling, so the later possible exception in inventory cannot be caught using
exceptionally
as it would not guarantee the cost was decremented - The inventory give item refunds the cost on failure, which returns another future. you cannot handle exceptions in a compose function so you have to propagate this some how.
It makes a lot more sense to use transactions here as that would simplify the code and provide a greater guarantee of database consistency, but I'll assume that these are microservices being called or something and you can't do that.
The solution i came up with is similar to @slisaasquatch
public CompletableFuture<Boolean> buyItem(String itemTypeId, int cost) {
return bank.decrement(cost).thenCompose(success -> {
if(!success) return completedFuture(false);
return inventory.giveItem(itemTypeId)
.thenApply(result -> completedFuture(true))
.exceptionally(inventoryException -> bank.refund(cost)
.handle((refundResult, refundException) -> {
throw new AppException(inventoryException);
}))
.thenCompose(f -> f);
});
}
Thanks for making this project and for the interesting challenge haha.
I guess there are really specific circumstances where futures just create syntax spaghetti and it becomes hard to follow.