If I use status 400 to handle "invalid input", with @HystrixCommand I'm able to specify set of exceptions (assuming custom error decoder) to be treated as "handled" and they won't break the circuit. With use of HystrixFeign.builder I have to remove @HystrixCommand and I do not see the way to specify my custom exceptions as well as how to specify that http 400 should not break circuit.

Comment From: tjuchniewicz

@vasilievip It would be great to have it integrated into @FeignClient.

Maybe it will help you: If you have custom ErrorDecoder you can apply it to @FeignClient and return HystrixBadRequestException from there and this will not break circuit.

Comment From: vasilievip

Maybe it will help you: If you have custom ErrorDecoder

Thanks! Will try it, but I would rather consider this as a workaround.

What I did already - disabled spring wired hystrix for my client and wrapped it into MyHystrixEnabledFeignClient with @HystrixCommand when I specify fallback and list of exceptions which are BadRequest ones.

Comment From: vasilievip

Thanks! Will try it, but I would rather consider this as a workaround.

BTW: As far as I remember - error decoder was executed after hystrix and not before

Comment From: tjuchniewicz

Could you share some code concept? How do you use @HystrixCommand with @FeignClient?

Comment From: tjuchniewicz

BTW: As far as I remember - error decoder was executed after hystrix and not before

Looks like before. I have working example for solution described above.

Comment From: vasilievip

I'll have to double check on it.

Here is some my code snippets:

@FeignClient(
        value = "BackupServer/buckets",
        configuration = {BackupServiceClientFeignContext.class}
)
public interface BackupServiceRestClient {
...

@Configuration
public class BackupServiceClientFeignContext {

    @Bean
    @Scope("prototype")
    @Primary
    //To disable hystrix
    public Feign.Builder feignBuilder() {
        return Feign.builder();
    }

    @Bean
    public ErrorDecoder cbsErrorDecoder() {
        return new BackupServiceClientFeignErrorDecoder();
    }
}
public class DefaultBackupServiceClientHystrixDecorator implements BackupServiceClientHystrixDecorator {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final BackupServiceRestClient restClient;

    public DefaultBackupServiceClientHystrixDecorator(BackupServiceRestClient restClient) {
        this.restClient = restClient;
    }

    @HystrixCommand(
            fallbackMethod = "getValueFallback",
            ignoreExceptions = {NoRecordFoundException.class, BucketAbsentException.class},
            commandProperties =
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")

    )
    @Metered(argIdToIncludeToMetrics = 0)
    public byte[] getValue(String bucket, String key) {
        try {
            return restClient.getRecord(stream, key);
        } catch (BackupServiceException e) {
            throw e;
        } catch (Exception e) {
            throw new ServiceUnavailableException(stream, key, e);
        }
    }

Comment From: vasilievip

fallbackMethod with throwable works for me from following version of javanica

<hystrix-javanica.version>1.4.25</hystrix-javanica.version>

Comment From: tjuchniewicz

Your solution with decorator is very interesting. Maybe I will use it ;-)

My current solution:

@FeignClient(
        value = "BackupServer/buckets",
        configuration = {BackupServiceClientFeignContext.class},
        fallback = BackupServiceRestClientFallback.class
)
public interface BackupServiceRestClient extends BackupServiceRest {
}

@Configuration
public class BackupServiceClientFeignContext {

    // Hystrix is enabled

    @Bean
    public ErrorDecoder cbsErrorDecoder() {
        // Decoder reads declared exceptions from interface method
        // and throws it when found in response wrapped in HystrixBadRequestException.
        // Service response contains custom entity with exception name occurred on service side.
        // or just converts 400-499 HTTP errors to HystrixBadRequestException
        return new BackupServiceClientFeignErrorDecoder(BackupServiceRest.class);
    }
}

@Component
public class DefaultBackupService {

    @Autowired
    private BackupServiceRestClient restClient;

    public byte[] getValue(String bucket, String key) {
        try {
            return restClient.getRecord(stream, key);
        } catch(HystrixBadRequestException e) {
            Throwable cause = e.getCause();
            if(cause instanceof NoRecordFoundException) {
                // cast to NoRecordFoundException
            }
        }
    }
}

Comment From: vasilievip

Looks like before. I have working example for solution described above.

Just tested and your approach with HystrixBadRequestException works fine as well, thanks!

Comment From: OlgaMaciaszek

Closing as Hystrix is no longer supported.