Microservices with NetflixOSS: Ribbon part 4

This is the next post on the services of bulding a microservice with the netflix stack . If you did not read the previous posts i recomed you do:

* NetflixOSS The DevOps Stack for MicroServices - http://diego-pacheco.blogspot.com/2015/09/netflixoss-devops-stack-for.html
* Microservices with NetflixOSS: Karyon, Ribbon and Eureka part 1 - http://diego-pacheco.blogspot.com/2015/09/microservices-with-netflixoss-karyon.html
* Microservices with NetflixOSS: Building and Running Eureka part 2 - http://diego-pacheco.blogspot.com/2015/09/microservices-with-netflixoss-building.html
* Microservices with NetflixOSS: Karyon and Services part 3 - http://diego-pacheco.blogspot.com/2015/09/this-is-next-post-on-services-of.html


Now is the time to introduce Ribbon. So we gonna create a very simple client that will call our REST Service we did on the previous post. We will need eureka client in order to tell ribbon how to get the IP of the service - first of all we need configure the client with this config here: eureka-client.properties

eureka.region=default
eureka.name=weather-service
eureka.vipAddress=localhost
eureka.port=6002
eureka.preferSameZone=true
eureka.shouldUseDns=false
eureka.us-east-1.availabilityZones=default
eureka.serviceUrl.default=http://localhost:8080/eureka/v2/
#
# Because i`m not running on Amazon
#
eureka.validateInstanceId=false


This code could be used for several reasons, for instance this could be another microservice calling our microservice, this also could be a website. We just need 3 classe todo the job :-)

The Classes

ApiFallbackHandler -> This is fall back implementation is the code will be run when service call fails.
ApiResponseValidator -> This validates the response to check if everything is ok.
RibbonClientUsingEureka -> This is the ribbon client using eureka.

ApiResponseValidator

You can use this class to throw errors in case the anwser is not proper - for this case im just logging but keep in my this is not just for logging.

@SuppressWarnings("rawtypes")
public class ApiResponseValidator implements ResponseValidator<HttpClientResponse> {
@Override
public void validate(HttpClientResponse response) throws UnsuccessfulResponseException,ServerError {
System.out.println("Validator: " + response);
}
}


ApiFallbackHandler

This is important for the sense of Anti-fragility because here we can do other thing if the service is down or even return something is wrong or incosistent. The code is kinda of confusing because we need use RxJava to have non-blocking IO.

public class ApiFallbackHandler implements FallbackHandler<ByteBuf> {
@Override
public Observable<ByteBuf> getFallback(HystrixInvokableInfo<?> hystrixInfo,Map<String, Object> requestProperties) {
return Observable.from(
new java.util.concurrent.Future<ByteBuf>(){
ByteBuf buf = Unpooled.wrappedBuffer(("Error on call api " + hystrixInfo + " : " + requestProperties).getBytes());
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
public boolean isCancelled() {
return false;
}
public boolean isDone() {
return true;
}
public ByteBuf get() throws InterruptedException,ExecutionException {
return buf;
}
public ByteBuf get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return buf;
}
});
}
}


RibbonClientUsingEureka

public class RibbonClientUsingEureka {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
// http://localhost:6002/weather/now/gravatai
System.out.println("apiCall.ribbon.MaxAutoRetriesNextServer: " + ConfigurationManager.getConfigInstance().getProperty("apiCall.ribbon.MaxAutoRetriesNextServer"));
System.out.println("apiCall.ribbon.ConnectTimeout: " + ConfigurationManager.getConfigInstance().getProperty("apiCall.ribbon.ConnectTimeout"));
System.out.println("apiCall.ribbon.ReadTimeout: " + ConfigurationManager.getConfigInstance().getProperty("apiCall.ribbon.ReadTimeout"));
System.out.println("Using eureka: " + new DefaultEurekaClientConfigProvider().get().getEurekaServerServiceUrls("default"));
LifecycleInjectorBuilder builder = LifecycleInjector.builder();
Injector injector = builder.build().createInjector();
EurekaClient client = injector.getInstance(EurekaClient.class);
InstanceInfo info = client.getApplication("WEATHER-SERVICE").getInstances().get(0);
String server = "http://" + info.getVIPAddress() + ":" + info.getPort();
System.out.println("Eureka Discovery client using: " + server);
HttpResourceGroup httpRG = Ribbon.createHttpResourceGroup("apiCall",
ClientOptions.create()
.withMaxAutoRetriesNextServer(1)
.withConfigurationBasedServerList(server)
);
HttpRequestTemplate<ByteBuf> apiTemplate = httpRG.newTemplateBuilder("apiCall",ByteBuf.class)
.withMethod("GET")
.withUriTemplate("/weather/now/gravatai")
.withFallbackProvider(new ApiFallbackHandler())
.withResponseValidator(new ApiResponseValidator())
.build();
RibbonResponse<ByteBuf> result = apiTemplate.requestBuilder()
.build()
.withMetadata().execute();
ByteBuf buf = result.content();
String json = buf.toString(Charset.forName("UTF-8" ));
System.out.println("Result in Json: " + json);
Gson gson = new Gson();
Map<String, String> mapResult = gson.fromJson(json, new TypeToken<Map<String, String>>() {}.getType());
System.out.println("Result weather: " + mapResult.get("weather"));
System.exit(0);
}
}
Here is were the magic happens. I`m using the Ribbon Code Template to call our service. You can see we are using Eureka Client API to retrieve the service HOST and PORT. When you use Ribbon you are using Hystrix for free so this code is protected - you will have retrys, load balancers, time outs, caching and much more :-)

Lalter i`m just using the Google Gson library to process the JSON response. That`s it you have a microservice calling another microservice using Ribbon, Hystrix, Eureka and Karyon. You also can get the full code on my github https://github.com/diegopacheco/netflixoss-pocs/tree/master/ribbon-eureka-client

Cheers,
Diego Pacheco

Popular posts from this blog

Having fun with Zig Language

C Unit Testing with Check

Cool Retro Terminal