I am trying to understand how Hystrix works with non-fault errors and the HystrixBadRequestException
, particularly in the area of validation. I use JSR-303 bean validation (Hibernate validator) for all my beans:
public class User {
@Min(1L)
private Long id;
@NotNull
@Email
private String email;
}
public class UserValidator {
private Validator validator;
// Throw exception if the user is invalid; return void otherwise.
public void validateUser(User user) {
Set<ConstraintViolation<User>> violations = validator.validate(user);
if(!violations.isEmpty()) {
return new BadEntityException(violations);
}
}
}
// Hystrix command.
public class SaveUserCommand extends HystrixCommand<User> {
public User user;
public void doSaveUser(User user) {
this.user = user;
execute();
}
@Override
protected User run() {
// Save 'user' somehow
}
@Override
protected User getFallback() {
return null;
}
}
// My service client that uses my Hystrix command.
public class UserClient {
private SaveUserCommandFactory factory = new SaveUserCommandFactory();
private UserValidator validator = new UserValidator();
public User saveUser(User user) {
SaveUserCommand saveUserCommand = factory.newSaveUserCommand();
validator.validate(user);
user = saveUserCommand.doSaveUser(user);
return user;
}
}
While this should work, I feel like the HystrixBadRequestException
was created for this purpose, and I could somehow be putting the validator
inside the command (not outside of it). According to the docs, this exception was intended for non-fault exceptions, including illegal arguments. I'm just not seeing how I could put my validation inside the command and leverage it (such that failed validations don't count against my metrics/stats).
It turns out you need to throw the
HystrixBadRequestException
inside theHystrixCommand
impl. In my case, the solution was to move the validator into theSaveUserCommand#run()
method:Now, if validation fails, the outer exception is a
HystrixBadRequestException
and it will not count against circuit breaker stats or published metrics.