I'm using Netflix' Hystrix libraries to act as a circuit breaker when connecting to remote services in a REST client I am building. I would like to setup the event streaming and dashboard monitoring via the libraries they provide. Looking at their example application here, it appears that I need to apply their servlet filters and servlet classes to my web application.
I'm using Spring Boot with Jersey 2 and wiring up my resources and filters in a JerseyConfig.java (no web.xml). I know that Jersey Filters are not the same as Servlet Filters and am struggling to integrate the two together.
So, how do you take a Java Servlet Filter and make it work as a Jersey Filter and how do you take a Java Servlet and make it work as a Jersey Resource?
My current strategy for the Servlets is to wrap them like so. One for each.
@Path("/hystrix.stream")
public class HystrixResource extends HystrixUtilizationSseServlet {
@Context
HttpServletRequest httpRequest;
@Context
HttpServletResponse httpResponse;
//This returns void because it is a text/stream output that must remain open,
//so the httpResponse is continually written to until the conenction is closed
@GET
public void doGet() throws ServletException, IOException {
doGet(httpRequest, httpResponse);
}
}
This might be working, but the data is basically empty for some reason. I am guessing that reason is because the Filters are not working.
data: {"type":"HystrixUtilization","commands":{},"threadpools":{}}
It is less clear to me how to wrap the Servlet Filters because they expect different inputs and outputs than a Jersey ContainerRequestFilter. The following implementation in my JerseyConfig seems to do nothing because the logs are not indicating that the filters are being registered and I cannot break on lines in these files in debug mode.
@Component
@ApplicationPath("/")
public class JerseyConfig extends ResourceConfig {
private static final Logger LOGGER = Logger.getLogger("JerseyConfig");
public JerseyConfig(){
//filter to provide a bridge between JAX-RS and Spring request attributes
register(RequestContextFilter.class);
register(SpringComponentProvider.class);
//handles custom serialization
register(new ObjectMapperContextResolver());
//try to register the filters - which doesn't work because these aren't Jersey Filters
register(HystrixRequestContextServletFilter.class);
register(HystrixRequestLogViaResponseHeaderServletFilter.class);
registerResources();
/*
* Enable the logging filter to see the HTTP response for each request.
*/
register(new LoggingFilter(LOGGER, true));
}
}
An alternative route, and the one I ended up eventually going with, is to use the Spring cloud/boot starters if you're in a Spring Boot project. This prevented me from having to explicitly define beans and filters as shown in the other answer. Eventually basically worked out of the box.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<exclusions>
<!--We're running our Jersey server w/ Jackson 2. This import uses Jackson 1.x and creates a breaking conflict.-->
<exclusion>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Reference Circuit Breaker getting started guide. The one issue I faced was the Jackson 1 vs Jackson 2 conflict and was able to add the library exclusion. I basically had the Hystrix library jar before, but nothing wired up to make it work.