У меня есть метод, который был бы подобен этому в традиционном императивном 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 part и попробуйте
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()
.