Feign Hystrix module provides circuit breaker support through Netflix Hystrix, enabling fault tolerance and fallback mechanisms for HTTP clients.
Enhanced Feign builder with circuit breaker and fallback support.
/**
* Feign builder with Hystrix circuit breaker integration
*/
public final class HystrixFeign {
/** Create new Hystrix-enabled Feign builder */
public static Builder builder();
/**
* Builder for Hystrix-enabled Feign clients
*/
public static final class Builder extends Feign.Builder {
/** Set invocation handler factory */
public Builder invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory);
/** Create client with fallback implementation */
public <T> T target(Class<T> apiType, String url, T fallback);
/** Create client with custom target and fallback */
public <T> T target(Target<T> target, T fallback);
/** Create client without fallback */
public <T> T target(Class<T> apiType, String url);
/** Create client with custom target */
public <T> T target(Target<T> target);
}
}Internal handler that wraps method calls in Hystrix commands.
/**
* Invocation handler that wraps method calls in Hystrix commands
*/
final class HystrixInvocationHandler implements InvocationHandler {
/** Handle method invocation with circuit breaker */
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}Contract that delegates to another contract while preserving Hystrix functionality.
/**
* Contract decorator that preserves Hystrix functionality
*/
final class HystrixDelegatingContract implements Contract {
/** Delegate contract processing to wrapped contract */
public List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType);
}import feign.hystrix.HystrixFeign;
import feign.gson.GsonDecoder;
// Simple circuit breaker without fallback
GitHub github = HystrixFeign.builder()
.decoder(new GsonDecoder())
.target(GitHub.class, "https://api.github.com");
// Method calls are automatically wrapped in Hystrix commands
List<Contributor> contributors = github.contributors("netflix", "feign");interface UserAPI {
@RequestLine("GET /users/{id}")
User getUser(@Param("id") String userId);
@RequestLine("GET /users")
List<User> getAllUsers();
}
// Fallback implementation
class UserAPIFallback implements UserAPI {
@Override
public User getUser(String userId) {
return new User("unknown", "Unknown User");
}
@Override
public List<User> getAllUsers() {
return Collections.emptyList();
}
}
// Create client with fallback
UserAPI userAPI = HystrixFeign.builder()
.decoder(new GsonDecoder())
.target(UserAPI.class, "https://api.example.com", new UserAPIFallback());
// Fallback is called when circuit breaker opens
User user = userAPI.getUser("123"); // Returns fallback data if service fails// Configure Hystrix properties via system properties or configuration
System.setProperty("hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds", "5000");
System.setProperty("hystrix.command.default.circuitBreaker.requestVolumeThreshold", "20");
System.setProperty("hystrix.command.default.circuitBreaker.errorThresholdPercentage", "50");
GitHub github = HystrixFeign.builder()
.decoder(new GsonDecoder())
.target(GitHub.class, "https://api.github.com");// Access Hystrix metrics for monitoring
HystrixCommandMetrics metrics = HystrixCommandMetrics.getInstance(
HystrixCommandKey.Factory.asKey("GitHub#contributors(String,String)")
);
// Get current circuit breaker status
boolean isCircuitBreakerOpen = metrics.getHealthCounts().getErrorPercentage() > 50;@Component
public class GitHubClient {
private final GitHub github;
public GitHubClient() {
this.github = HystrixFeign.builder()
.decoder(new GsonDecoder())
.target(GitHub.class, "https://api.github.com", new GitHubFallback());
}
public List<Contributor> getContributors(String owner, String repo) {
return github.contributors(owner, repo);
}
}
@Component
class GitHubFallback implements GitHub {
@Override
public List<Contributor> contributors(String owner, String repo) {
// Return cached data or empty list
return Collections.emptyList();
}
}// Circuit breaker with JAX-RS annotations
UserAPI userAPI = HystrixFeign.builder()
.contract(new JAXRSContract())
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.logger(new Slf4jLogger())
.logLevel(Logger.Level.BASIC)
.target(UserAPI.class, "https://api.example.com", new UserAPIFallback());Add the Hystrix module dependency:
dependencies {
compile 'com.netflix.feign:feign-hystrix:8.18.0'
compile 'com.netflix.hystrix:hystrix-core:1.5.18'
}Configure via system properties or Hystrix configuration:
// Timeout configuration
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
// Circuit breaker configuration
hystrix.command.default.circuitBreaker.requestVolumeThreshold=20
hystrix.command.default.circuitBreaker.errorThresholdPercentage=50
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=5000
// Thread pool configuration
hystrix.threadpool.default.coreSize=10
hystrix.threadpool.default.maxQueueSize=100// Configure specific methods
hystrix.command.GitHub#contributors(String,String).execution.isolation.thread.timeoutInMilliseconds=10000
hystrix.command.UserAPI#getUser(String).circuitBreaker.errorThresholdPercentage=30Enable Hystrix metrics stream for monitoring:
// Add Hystrix metrics servlet to web application
@WebServlet("/hystrix.stream")
public class HystrixMetricsStreamServlet extends HystrixMetricsStreamServlet {
}// Collect custom metrics
public class MetricsCollector {
public void collectCircuitBreakerMetrics() {
for (HystrixCommandKey key : HystrixCommandKey.Factory.asKey("GitHub")) {
HystrixCommandMetrics metrics = HystrixCommandMetrics.getInstance(key);
long executionCount = metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS);
long failureCount = metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE);
// Log or send to monitoring system
}
}
}