Enterprise Java

Spring Cloud support for Hystrix

Spring Cloud project provides comprehensive support for Netflix OSS Hystrix library. I have previously written about how to use the raw Hystrix library to wrap remote calls. Here I will be going over how Hystrix can be used with Spring Cloud

Basics

There is actually nothing much to it, the concepts just carry over with certain Spring boot specific enhancements. Consider a simple Hystrix command, that wraps around a call to a Remote service:

import agg.samples.domain.Message;
import agg.samples.domain.MessageAcknowledgement;
import agg.samples.feign.RemoteServiceClient;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RemoteMessageClientCommand extends HystrixCommand<MessageAcknowledgement> {
    private static final String COMMAND_GROUP = "demo";
    private static final Logger logger = LoggerFactory.getLogger(RemoteMessageClientCommand.class);

    private final RemoteServiceClient remoteServiceClient;
    private final Message message;

    public RemoteMessageClientCommand(RemoteServiceClient remoteServiceClient, Message message) {
        super(HystrixCommandGroupKey.Factory.asKey(COMMAND_GROUP));
        this.remoteServiceClient = remoteServiceClient;
        this.message = message;
    }

    @Override
    protected MessageAcknowledgement run() throws Exception {
        logger.info("About to make Remote Call");
        return this.remoteServiceClient.sendMessage(this.message);
    }

    @Override
    protected MessageAcknowledgement getFallback() {
        return new MessageAcknowledgement(message.getId(), message.getPayload(), "Fallback message");
    }
}

There are no Spring related classes here and this command can be used directly in a Spring based project, say in a controller the following way:

@RestController
public class RemoteCallDirectCommandController {

    @Autowired
    private RemoteServiceClient remoteServiceClient;

    @RequestMapping("/messageDirectCommand")
    public MessageAcknowledgement sendMessage(Message message) {
        RemoteMessageClientCommand remoteCallCommand = new RemoteMessageClientCommand(remoteServiceClient, message);
        return remoteCallCommand.execute();
    }
}

The customization of behavior of a Hystrix command is normally performed through NetflixOSS Archaius properties, however Spring Cloud provides a bridge to make the Spring defined properties visible as Archaius properties, this in short means that I can define my properties using Spring specific configuration files and they would be visible when customizing the command behavior.

So if were earlier customizing say a HelloWorldCommand’s behavior using Archaius properties which look like this:

hystrix.command.HelloWorldCommand.metrics.rollingStats.timeInMilliseconds=10000
hystrix.command.HelloWorldCommand.execution.isolation.strategy=THREAD
hystrix.command.HelloWorldCommand.execution.isolation.thread.timeoutInMilliseconds=1000
hystrix.command.HelloWorldCommand.circuitBreaker.errorThresholdPercentage=50
hystrix.command.HelloWorldCommand.circuitBreaker.requestVolumeThreshold=20
hystrix.command.HelloWorldCommand.circuitBreaker.sleepWindowInMilliseconds=5000

this can be done in the Spring Cloud world the exact same way in a application.properties file or in a application.yml file the following way:

hystrix:
  command:
    HelloWorldCommand:
      metrics:
        rollingStats:
          timeInMilliseconds: 10000
      execution:
        isolation:
          strategy: THREAD
          thread:
            timeoutInMilliseconds: 5000
      circuitBreaker:
        errorThresholdPercentage: 50
        requestVolumeThreshold: 20
        sleepWindowInMilliseconds: 5000

Annotation based Approach

I personally prefer the direct command based approach, however a better approach for using Hystrix in the Spring world may be to use hystrix-javanica based annotations instead. The use of this annotation is best illustrated with an example. Here is the remote call wrapped in a Hystrix command with annotations:

import agg.samples.domain.Message;
import agg.samples.domain.MessageAcknowledgement;
import agg.samples.feign.RemoteServiceClient;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class RemoteMessageAnnotationClient  {

    private final RemoteServiceClient remoteServiceClient;

    @Autowired
    public RemoteMessageAnnotationClient(RemoteServiceClient remoteServiceClient) {
        this.remoteServiceClient = remoteServiceClient;
    }

    @HystrixCommand(fallbackMethod = "defaultMessage", commandKey = "RemoteMessageAnnotationClient" )
    public MessageAcknowledgement sendMessage(Message message) {
        return this.remoteServiceClient.sendMessage(message);
    }

    public MessageAcknowledgement defaultMessage(Message message) {
        return new MessageAcknowledgement("-1", message.getPayload(), "Fallback Payload");
    }

}

These annotations are translated using an aspect into a regular Hystrix commands behind the scenes, the neat thing though is that there is no ceremony in using this in a Spring Cloud project, it just works. Like before if the behavior needs to be customized it can be done with the command specific properties. One small catch is that the command name by default is the method name, so in my example the command name would have been “sendMessage”, which I have customized using the annotation to be a different name.

Reference: Spring Cloud support for Hystrix from our JCG partner Biju Kunjummen at the all and sundry blog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Sajid Nawaz
Sajid Nawaz
8 years ago

it is good website for learning.

Back to top button