Cette page suppose une application CDI 4.1 Lite déjà fonctionnelle sur Vauban (ou tout autre container compatible CDI Lite). Elle décrit l’ajout de Heisenberg : dépendances Maven, annotations minimales, comportement attendu.

Prérequis

  • Java 25 (LTS) — Temurin recommandé.

  • Maven 3.9.16 — épinglé par .sdkmanrc à la racine de Heisenberg.

  • Une application CDI 4.1 déjà déployée, avec au moins un bean @ApplicationScoped.

sdk env                              # Java 25 + Maven 3.9.16
./mvnw -ntp install -DskipTests     # installe heisenberg-api, heisenberg-core, heisenberg-cdi-vauban

Dépendances Maven

heisenberg-cdi-vauban apporte l’intercepteur et la BCE Vauban ; il tire transitivement heisenberg-core (les moteurs purs) et heisenberg-api (la SPI). Une seule entrée suffit dans le pom.xml applicatif.

<dependencies>
    <dependency>
        <groupId>io.vidocq.heisenberg</groupId>
        <artifactId>heisenberg-cdi-vauban</artifactId>
        <version>0.1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.microprofile.fault-tolerance</groupId>
        <artifactId>microprofile-fault-tolerance-api</artifactId>
        <version>4.1</version>
    </dependency>
</dependencies>

L’API MicroProfile Fault Tolerance est déclarée en provided dans heisenberg-cdi-vauban. Elle apporte les annotations @Retry, @Timeout, @CircuitBreaker, @Bulkhead, @Fallback, @Asynchronous à utiliser dans le code applicatif. La variante modularisée io.vidocq.heisenberg:heisenberg-mp-ft-api peut la remplacer dans un projet entièrement jlink-compatible.

Première méthode protégée

Annotez une méthode de bean CDI. L’intercepteur Heisenberg compose les politiques de l’extérieur vers l’intérieur — @Fallback enveloppe @CircuitBreaker, qui enveloppe @Bulkhead, @Timeout et @Retry, qui finissent par appeler la méthode réelle.

package io.example;

import jakarta.enterprise.context.ApplicationScoped;
import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
import org.eclipse.microprofile.faulttolerance.Fallback;
import org.eclipse.microprofile.faulttolerance.Retry;

@ApplicationScoped
public class InventoryClient {

    @Retry(maxRetries = 3, delay = 200)
    @CircuitBreaker(requestVolumeThreshold = 10, failureRatio = 0.5, delay = 5000)
    @Fallback(fallbackMethod = "cachedStock")
    public Stock currentStock(String sku) {
        // appel distant susceptible d'échouer ou de se bloquer
        return remote.fetch(sku);
    }

    // la signature du repli doit correspondre au type de retour de la méthode protégée
    private Stock cachedStock(String sku) {
        return Stock.empty(sku);
    }
}

Sémantique :

  • @Retry ré-invoque la méthode jusqu’à maxRetries=3 fois avec delay=200 ms entre les tentatives.

  • @CircuitBreaker s’ouvre dès que failureRatio=0.5 est atteint sur la fenêtre requestVolumeThreshold=10, court-circuitant les appels suivants pendant delay=5000 ms (état OPEN) avant de passer en HALF_OPEN.

  • @Fallback fournit le résultat alternatif lorsque l’appel protégé finit par échouer (toutes les tentatives ont échoué ou le circuit est ouvert).

Démarrer le container

Aucun bootstrap supplémentaire. La BCE Vauban (HeisenbergExtension) découvre l’intercepteur au démarrage et l’enregistre pour tous les beans annotés. Lancer l’application via Vauban.bootstrap() ou via Cassini / Foy suffit.

# Démarre l'application — la BCE Heisenberg s'auto-enregistre
java -p mods -m io.example/io.example.App

Vérifier visuellement

Provoquer un échec en coupant le service distant. Les traces de la chaîne d’intercepteurs sont disponibles via les recorders d’observabilité — voir FtMetricsRecorder.

curl -i http://localhost:8080/api/stock/SKU-42
# 200 OK + body { "sku": "SKU-42", "qty": 0 }   <- cachedStock après 3 retries

Surcharger sans recompiler

Tous les paramètres d’annotation sont surchargeables via MicroProfile Config (clés fault-tolerance/<bean>/<méthode>/<Annotation>/<paramètre>). Voir Référence.

# Désactive @Retry sur cette méthode sans toucher au code
fault-tolerance/io.example.InventoryClient/currentStock/Retry/maxRetries=0

# Allonge le timeout du circuit breaker en environnement lent
fault-tolerance/io.example.InventoryClient/currentStock/CircuitBreaker/delay=10000

La précédence MP FT 4.1 §12 reste classique : méthode-cible > classe > valeur par défaut de l’annotation. La clé sans qualifiant fault-tolerance/<Annotation>/<paramètre> agit comme valeur globale.

Trois sources d’annotation combinables

Source Description Activation

Annotation directe

@Retry posée sur la méthode ou la classe.

Automatique.

Annotation de classe héritée

@Bulkhead posée sur la classe, vue par toutes ses méthodes.

Automatique (spec §9.3).

MicroProfile Config

Clé fault-tolerance/…​ lue par Ravel.

Présence de la clé suffit.

Désactiver entièrement la tolérance aux pannes

Pour des tests d’intégration où la lenteur du retry est gênante :

fault-tolerance/MP_Fault_Tolerance_NonFallback_Enabled=false
fault-tolerance/MP_Fault_Tolerance_Metrics_Enabled=false

MP_Fault_Tolerance_NonFallback_Enabled=false désactive @Retry, @Timeout, @CircuitBreaker, @Bulkhead et @Asynchronous ; @Fallback reste actif conformément à la spec §11.

Étape suivante

  • Concepts — ordre de composition, états du circuit breaker, sémantique de @Asynchronous.

  • Cas d’usage — clients REST robustes, FallbackHandler typé, virtual threads.

  • Référence — toutes les annotations, tous les paramètres, toutes les clés fault-tolerance/*.