3

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));
    }
}
th3morg
  • 4,321
  • 1
  • 32
  • 45

2 Answers2

1

Servlets and Servlet filters should not be registered in the Jersey config. They will simply be ignored. You should instead be registering them with Spring Boot with ServletRegistrationBeans and FilterRegistrationBeans.

In you Spring configuration, you can do something like

@Bean
public ServletRegistrationBean someServlet() {
    ServletRegistrationBean registration = ServletRegisrationBean(
            new HystrixMetricsStreamServlet(), "/hystrix.stream");
    registration.setName("HystrixMetricsStreamServlet");
    return registration;
}

@Bean
public FilterRegistrationBean someFilter() {
    FilterRegistrationBean registration = new FilterRegistrationBean();
    registration.setFilter(new HystrixRequestContextServletFilter());
    registration.setUrlPatterns(Arrays.asList("/*"));
    registration.setName("HystrixRequestContextServletFilter");
    // you can also set the order of filters if you need to 
    return registration;
}

Also:

  • you don't need to register the SpringComponentProvider. This is automatically registered.
  • If you get a 404 on trying to access the servlet being registered this way, it will be because you are using the default Jersey mapping /*, which hogs up all the request. You can change the mapping or register Jersey as a filter to forward not found requests. See this post
Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • Hi @peeskillet. Thank you for your reply. I'm not serving pages through spring web, so will any of your response be applicable? – th3morg Jun 30 '16 at 00:05
  • What does serving pages have to do with anything? You have tagged Spring Boot, so I am giving you the Spring Boot solution. I don't see where serving pages fits it anywhere to the problem. – Paul Samsotha Jun 30 '16 at 00:28
  • Thank you @peeskillet. I was able to get this working based on your suggestion. It's potentially important to note that the servlet for hystrix.stream should be HystrixMetricsStreamServlet, not the HystrixUtilizationSseServlet. I'll try to make that edit. Secondly, no data will be present until a Command is executed. So, if you restart your application, your data will be empty until requests are passing through your HystrixCommands. Thanks! – th3morg Jan 03 '17 at 19:34
0

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.

th3morg
  • 4,321
  • 1
  • 32
  • 45