Basics
There is actually nothing much to it, the raw Hystrix 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.
If you are interested in exploring this sample further, here is my github project.
If I use the javanica anotations can i use the spring configuration yml Syntax to configuration EG timeout Outsider the code/anotations. Which one eins if I have both (code and cfg). Do I have placeholders in the anotations to configuration from outside/yml. Are Theresa any useful PatterNS if I use Spring cloud+ribbon+hystrix. Eher are advantages for fein, eher not in this Stack?
ReplyDelete