我有一种方法,在传统的命令式try-catch
编码风格中是这样的:
void confirmCart(Checkout Order) {
try {
cartService.confirm(order.getCartId(), order.getCartHash());
} catch (Exception ex1) {
log.error("Confirm error: ", ex1);
try {
paymentService.cancel(order.getPaymentTransaction().getGatewayReference());
throw ServiceException.wrap(ex1, CheckoutErrorCode.FAILED_CONFIRMING_CART);
} catch (Exception ex2) {
throw ServiceException.wrap(ex2, CheckoutErrorCode.FAILED_CANCELLING_PAYMENT);
}
}
}
要求是:
- 工作时
cartService.confirm()
,不返回任何内容 - 失败时进入catch部分,尝试
paymentService.cancel()
- 如果 2 失败,则抛出
ex2
- 如果 2 成功,则抛出
ex1
(因为confirm()
无论如何都失败了) - 根据这里抛出的异常,控制器会做不同的事情
现在,在 Reactive 风格中,它就像:
Mono<Void> confirmCart(CheckoutOrder order) {
return cartService.confirm(order.getCartId(), order.getCartHash())
.onErrorMap(throwable -> {
log.error("Failed confirming cart! cartId: '{}', cartHash: '{}'", order.getCartId(), order.getCartHash(), throwable);
return ServiceException.wrap(throwable, CheckoutErrorCode.FAILED_CONFIRMING_CART);
})
.onErrorResume(throwable -> {
log.trace("Cancelling payment with order id {}", order.getId().toString());
// when confirmation fails, 1. cancel payment and 2. throw original exception to notify controller -> exception handler
return paymentService.cancel(order.getPaymentTransaction().getGatewayReference())
.map(paymentCancellationResponse -> {
log.trace("payment cancellation response: {}, order id: {}", paymentCancellationResponse, order.getId().toString());
return paymentCancellationResponse;
}).then()
.onErrorMap(e -> {
log.error("payment payment cancellation failed. ", e);
return ServiceException.wrap(e, CheckoutErrorCode.FAILED_CANCELLING_PAYMENT);
});
});
}
但是,我花了很多时间与 Reactive 运算符一起玩,但找不到任何方法来重新抛出原始异常。上面的代码可以编译,但是失败时不会抛出第一个异常confirmCart()
。我猜是因为onErrorMap()
和onErrorResume()
不能共存;后一个会很荣幸,也许吧?
我已经尝试过,onErrorMap
因为此外,它应该是同步的:如果失败则confirmCart()
应该等待。paymentService.cancel()
我在玩then()
,thenReturn()
等等,但我可以让它编译,但它不会返回/重新抛出第一个确认异常。
return cartService.confirm(order.getCartId(), order.getCartHash())
.onErrorResume(throwable -> {
log.error("Failed confirming cart! cartId: '{}', cartHash: '{}'", order.getCartId(), order.getCartHash(), throwable);
log.trace("Cancelling payment with order id {}", order.getId().toString());
// when confirmation fails, 1. cancel payment and 2. redirect user to checkout page
return paymentService.cancel(order.getPaymentTransaction().getGatewayReference())
.map(paymentCancellationResponse -> {
log.trace("payment cancellation response: {}, order id: {}", paymentCancellationResponse, order.getId().toString());
return paymentCancellationResponse;
}).thenReturn(
ServiceException.wrap(throwable, CheckoutErrorCode.FAILED_CONFIRMING_CART)
)
.onErrorMap(e -> {
log.error("payment payment cancellation failed. ", e);
return ServiceException.wrap(e, CheckoutErrorCode.FAILED_CANCELLING_PAYMENT);
}).then();
});
在测试中,失败时我没有抛出异常cartService.confirm()
。