Ratpack avec Hystrix

1. Introduction

Auparavant, nous avions montré comment créer une application hautes performances et réactive avec Ratpack.

Dans cet article, nous verrons comment intégrer Netflix Hystrix à une application Ratpack.

Netflix Hystrix permet de contrôler les interactions entre les services distribués en isolant les points d’accès pour arrêter les défaillances en cascade et en fournissant des options de secours pour la tolérance aux pannes. Cela peut nous aider à construire une application plus résiliente. Voir notre lien:/introduction-to-hystrix[introduction à Hystrix]pour un aperçu rapide.

C’est ainsi que nous allons l’utiliser: nous allons améliorer notre application Ratpack avec ces fonctionnalités utiles fournies par Hystrix.

2. Dépendance Maven

Pour utiliser Hystrix avec Ratpack, nous avons besoin de la dépendance ratpack-hystrix dans le projet pom.xml :

<dependency>
    <groupId>io.ratpack</groupId>
    <artifactId>ratpack-hystrix</artifactId>
    <version>1.4.6</version>
</dependency>

La dernière version de ratpack-hystrix est disponible sur ici .

Pour utiliser les fonctions réactives de Ratpack, nous aurions également besoin de ratpack-rx:

<dependency>
    <groupId>io.ratpack</groupId>
    <artifactId>ratpack-rx</artifactId>
    <version>1.4.6</version>
</dependency>

3. Servir avec Hystrix Command

Lors de l’utilisation de Hystrix, les services sous-jacents sont généralement encapsulés dans HystrixCommand ou HystrixObservableCommand .

Hystrix prend en charge l’exécution de ces commandes de manière synchrone, asynchrone et réactive. Parmi ceux-ci, seul réactif est non bloquant et officiellement recommandé.

  • Dans les exemples suivants, nous allons créer des points finaux qui extraient un profil à partir de l’API REST Github . **

3.1. Exécution de commande réactive

Premièrement, construisons un service principal réactif avec Hystrix:

public class HystrixReactiveHttpCommand extends HystrixObservableCommand<String> {

   //...

    @Override
    protected Observable<String> construct() {
        return RxRatpack.observe(httpClient
          .get(uri, r -> r.headers(h -> h.add("User-Agent", "Baeldung HttpClient")))
          .map(res -> res.getBody().getText()));
    }

    @Override
    protected Observable<String> resumeWithFallback() {
        return Observable.just("eugenp's reactive fallback profile");
    }
}

Ici, un Ratpack réactif HttpClient est utilisé pour effectuer une demande GET. La HystrixReactiveHttpCommand peut fonctionner comme un gestionnaire réactif:

chain.get("rx", ctx ->
  new HystrixReactiveHttpCommand(
    ctx.get(HttpClient.class), eugenGithubProfileUri, timeout)
    .toObservable()
    .subscribe(ctx::render));

Le noeud final peut être vérifié avec le test suivant:

@Test
public void whenFetchReactive__thenGotEugenProfile() {
    assertThat(appUnderTest.getHttpClient().getText("rx"),
      containsString("www.baeldung.com"));
}

3.2. Exécution de commande asynchrone

Une exécution asynchrone de HystrixCommand met la commande en file d’attente sur le pool de threads et renvoie un Future :

chain.get("async", ctx -> ctx.render(
  new HystrixAsyncHttpCommand(eugenGithubProfileUri, timeout)
    .queue()
    .get()));

La HystrixAsyncHttpCommand se présente comme suit:

public class HystrixAsyncHttpCommand extends HystrixCommand<String> {

   //...

    @Override
    protected String run() throws Exception {
        return EntityUtils.toString(HttpClientBuilder.create()
          .setDefaultRequestConfig(requestConfig)
          .setDefaultHeaders(Collections.singleton(
            new BasicHeader("User-Agent", "Baeldung Blocking HttpClient")))
          .build().execute(new HttpGet(uri)).getEntity());
    }

    @Override
    protected String getFallback() {
        return "eugenp's async fallback profile";
    }

}

Nous utilisons ici un HttpClient bloquant au lieu d’un non-bloquant car nous souhaitons contrôler Hystrix le délai d’exécution de la commande réelle afin que nous n’ayons pas besoin de la gérer seule lorsque nous obtenons une réponse de Future . Cela permet également à Hystrix de se replier ou de mettre en cache notre requête.

L’exécution asynchrone produit également le résultat attendu:

@Test
public void whenFetchAsync__thenGotEugenProfile() {
    assertThat(appUnderTest.getHttpClient().getText("async"),
      containsString("www.baeldung.com"));
}

3.3. Exécution de commande synchrone

Une exécution synchrone exécute la commande directement dans le thread actuel:

chain.get("sync", ctx -> ctx.render(
  new HystrixSyncHttpCommand(eugenGithubProfileUri, timeout).execute()));

L’implémentation de HystrixSyncHttpCommand est presque identique à HystrixAsyncHttpCommand sauf que nous lui donnons un résultat de repli différent. Lorsqu’il ne recule pas, il se comporte exactement comme une exécution réactive et asynchrone:

@Test
public void whenFetchSync__thenGotEugenProfile() {
    assertThat(appUnderTest.getHttpClient().getText("sync"),
      containsString("www.baeldung.com"));
}

4. Métriques

En enregistrant le lien:/ratpack-google-guice[module Guice]- HystrixModule dans le registre Ratpack, nous pouvons diffuser la requête scop métriques et exposer les flux d’événements via un noeud final GET :

serverSpec.registry(
  Guice.registry(spec -> spec.module(new HystrixModule().sse())))
  .handlers(c -> c.get("hystrix", new HystrixMetricsEventStreamHandler()));

Le HystrixMetricsEventStreamHandler permet de diffuser des métriques Hystrix au format text/event-stream , de manière à pouvoir surveiller les métriques dans Hystrix Dashboard .

Nous pouvons configurer un tableau de bord standalone Hystrix et ajouter notre flux d’événements Hystrix à la liste des moniteurs pour voir comment notre application Ratpack fonctionne:

Après plusieurs demandes adressées à notre application Ratpack, nous pouvons voir les commandes liées à Hystrix dans le tableau de bord.

4.1. Sous la capuche

Dans HystrixModule , une Hystrix Concurrency Strategy est enregistrée auprès de Hystrix via HystrixPlugin pour gérer le contexte de la demande avec le registre Ratpack. Cela supprime la nécessité d’initialiser le contexte de la demande Hystrix avant le début de chaque demande.

public class HystrixModule extends ConfigurableModule<HystrixModule.Config> {

   //...

    @Override
    protected void configure() {
      try {
        HystrixPlugins.getInstance().registerConcurrencyStrategy(
          new HystrixRegistryBackedConcurrencyStrategy());
      } catch (IllegalStateException e) {
       //...
      }
    }

   //...

}

5. Conclusion

Dans cet article rapide, nous avons montré comment intégrer Hystrix à Ratpack et comment transférer les métriques de notre application Ratpack vers Hystrix Dashboard pour une meilleure vision des performances de l’application.

Comme toujours, la mise en œuvre complète peut être consultée sur le projet Github .