Usage of Executors[Q&C] With Exceptions

Here you can see how you can handle the success, failure and retryable scenario inside the query-executor executor. In the same way, you can handle all things in command-executor as well.

Create your own exception annotating with @SagaException class to handle to inactive user exception.

The executor gets the userdata from the user-service by calling another service. Based on the return of the userService.getUserDetail method, the next step is managed here. If the user is in active mode, The current executor allows the next executor by providing the next executor that should be invoked to the StackSaga engine.

@SagaExecutor(
        executeFor = "user-service",
        liveCheck = true,
        value = "CheckUserExecutor"
)
@AllArgsConstructor
public class CheckUserExecutor implements QueryExecutor<PlaceOrderAggregator> {

    private final UserService userService;

    @Override
    public ProcessStepManager<PlaceOrderAggregator> doProcess(
            ProcessStack processStack,
            PlaceOrderAggregator aggregator,
            ProcessStepManagerUtil<PlaceOrderAggregator> stepManagerUtil
    ) throws RetryableExecutorException, NonRetryableExecutorException {

        try {
            ResponseEntity<UserDetailDto> userDetail = this.userService.getUserDetail(aggregator.getUsername());
            if (userDetail.getBody().getIsActive() == 1) {
                return stepManagerUtil.next(DispatchOrderExecutor.class); (1)
            } else {
                UserInactiveException inactiveException = new UserInactiveException("User is not active!"); (2)
                throw NonRetryableExecutorException
                        .buildWith(inactiveException)
                        .build();
            }
        } catch (FeignException.ServiceUnavailable unavailableException) {
            throw RetryableExecutorException
                    .buildWith(unavailableException)
                    .build(); (3)
        } catch (FeignException.BadRequest badRequestException) {
            throw NonRetryableExecutorException
                    .buildWith(badRequestException)
                    .put("test", LocalDateTime.now())
                    .put("reason", "BadRequest")
                    .build(); (4)
        }
    }
}
1 Success scenario: If the user is active, the next executor will be provided to the engine by using stepManagerUtil.next() method.
2 Failed scenario: IF the user is inactive, the process is stopped to forward by throwing NonRetryableExecutorException with UserInactiveException.
3 Failed scenario: IF the userService.getUserDetail() service throw a FeignException.BadRequest exception, the process is stopped to forward by throwing NonRetryableExecutorException with FeignException.BadRequest that occurred.
4 Retryable scenario IF the userService.getUserDetail() service throw a FeignException.ServiceUnavailable exception, the process is stopped temporally by throwing NonRetryableExecutorException with FeignException.ServiceUnavailable that occurred.