> ## Content Index
> Fetch the complete content index at: https://www.sfeir.dev/llms.txt
> Use this file to discover other available public pages before exploring further.

# La taverne en flammes : un manuel de résilience opérationnelle pour Quarkus
- URL: https://www.sfeir.dev/back/la-taverne-en-flammes-un-manuel-de-resilience-operationnelle-pour-quarkus/
- Published: 2026-10-22T10:14:51.000Z
- Updated: 2026-10-22T10:14:51.000Z
- Description: Minuit, la cuisine de The Falling Whale prend feu ! Pas de panique : ce guide pratique met Quarkus à l’épreuve du chaos. Arrêt gracieux, sondes, timeouts et transactions robustes... découvrez comment maîtriser la résilience opérationnelle pour sauver votre service au milieu des flammes.
- Author: Erwan Le Tutour
- Tags: Back, Java, quarkus, Resilience, DevOps

Minuit passé, la cuisine de la taverne prend feu.   
Le tavernier ne peut pas fermer boutique sur le champ : il reste trois tournées en cours dans la salle commune, un corbeau qui vient de partir livrer une commande, une ligne du grand livre à moitié écrite.   
Ce qu'il fait dans le quart d'heure qui suit décide si la taverne s'en sort proprement ou si elle referme dans le chaos.

Chaque recoin de la maison porte un mécanisme de résilience bien précis. 

- La salle commune sert des tournées trop lentes pour tester l'arrêt gracieux.
- La cuisine cuisine trop lentement pour tester un timeout.
- La volière fait attendre ses corbeaux pour simuler un retard de messages.
- Le grand livre des comptes refuse de perdre une seule pièce d'or, quoi qu'il arrive.

Et cette nuit-là, un incendie se déclare dans la cuisine.

Avant de suivre l'incendie du début à la fin, voici qui tient quel poste cette nuit-là :

| Élément de la taverne      | Mécanisme Quarkus                    | Classe principale                                            |
| -------------------------- | ------------------------------------ | ------------------------------------------------------------ |
| La cuisine qui brûle       | Sondes de santé (liveness/readiness) | IncendieService, CharpenteHealthCheck, CaveABiereHealthCheck |
| La salle commune           | Arrêt gracieux                       | SalleCommuneService, ArretGracieuxObserver                   |
| La cuisine (les plats)     | Timeout réactif (Mutiny)             | CuisineService                                               |
| Le grimoire de la guilde   | Timeout déclaratif (Fault Tolerance) | GrimoireService, GrimoireDistant                             |
| La volière                 | Vidange de messages à l'arrêt        | VoliereService, ColombierListener                            |
| Le grand livre des comptes | Transactions JTA                     | GrandLivreService, LigneDeCompte                             |
| Le tavernier d'astreinte   | Runbook et post-mortem               | RunbookService, PostMortemService                            |

Le reste de l'article suit la nuit dans l'ordre où elle se déroule : le feu prend, les sondes le voient, chaque garde-fou est mis à l'épreuve l'un après l'autre, et le lendemain matin il faut en tirer les leçons.

## Allumer le feu

Dans la cuisine, la friture s'enflamme. Côté code, tout part d'un service assez simple, `IncendieService`, qui tient l'état de l'incident et sa chronologie.   
Deux booléens suffisent à raconter toute l'histoire : la cuisine brûle, ou elle ne brûle pas ; la charpente tient, ou elle s'est effondrée. 

C'est volontairement pauvre. Un vrai système de supervision porterait bien plus d'informations, mais réduire l'état à deux drapeaux permet de voir clairement, à chaque étape de l'article, quelle décision découle de quel drapeau.

```java
public EtatTaverne declencherIncendie(String origine) {
    String origineRetenue = (origine == null || origine.isBlank()) ? "friture de la cuisine" : origine;
    if (cuisineEnFeu.compareAndSet(false, true)) {
        origineIncendie.set(origineRetenue);
        noter("DEBUT_INCENDIE", "Le feu prend : " + origineRetenue);
        noter("TOCSIN", "La cloche sonne, la readiness passe DOWN, l'orchestrateur retire l'instance du routage");
    }
    return etat();
}

```

Un appel HTTP suffit à déclencher l'incendie :

```bash
curl -X POST "http://localhost:8086/taverne/incendie?origine=friture+de+la+cuisine"

```

La cloche sonne. Reste à savoir qui, dans la taverne, l'entend en premier, et ce que ça change vraiment pour le service.

## Le tableau de bord avant l'incendie

Derrière le comptoir, le tavernier a accroché un tableau qui résume l'état de chaque recoin de la maison, un coup d'œil suffit pour savoir si tout va bien avant même de descendre vérifier la cave. Dans le code, ce tableau existe déjà tout fait : [Quarkus](https://www.sfeir.dev/quarkus-definition/) l'appelle la Dev UI, accessible sur `/q/dev-ui` en mode développement.  
La page `SmallRye Health` y [liste tous les health checks de l'application](https://www.sfeir.dev/back/observer-la-taverne-en-pleine-effervescence-observabilite-avec-quarkus/), y compris ceux qu'on vient d'écrire soi-même, sans configuration supplémentaire.

Voici ce que ça donne à l'état initial, avant tout incendie : toutes les cartes sont vertes. 

- `Charpente de la taverne` affiche `poutres_maitresses: intactes`
- `Acces a la reserve de biere` affiche  
  - `temperature_cave: 12 C`
  - `escalier_praticable`
  - `origine_incendie: aucune`.

On y retrouve aussi les checks fournis gratuitement par les extensions installées : 

- la connexion à la base de données,
- les checks de liveness et readiness de SmallRye Reactive Messaging pour le canal de la volière
- le check `Graceful Shutdown` de Quarkus lui-même.

C'est un bon réflexe à prendre en développement local : avant de creuser dans les logs ou de multiplier les appels `curl`, un coup d'œil à cette page dit déjà si le problème vient d'une sonde en particulier, sans avoir à mémoriser l'URL de chacune.

![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/2026/08/image-12.png)

Avant l'incendie tout va bien

Ce soir-là pourtant, une carte va basculer au rouge avant les autres. C'est celle qui distingue vraiment tenir debout de pouvoir encore servir.

![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/2026/08/image-13.png)

Mais des que celui-ci se déclare...

## Les sondes : tenir debout n'est pas la même chose que servir

`CharpenteHealthCheck` répond à la question "l'instance doit-elle être détruite ?". `CaveABiereHealthCheck` répond à une question différente : "peut-on encore accueillir du monde ?".  
Tant que seule la cuisine brûle, la charpente reste intacte, la liveness reste UP, mais la readiness bascule DOWN.   
L'orchestrateur retire l'instance du routage sans la tuer, ce qui est exactement le comportement voulu : pas la peine de redémarrer un pod qui n'a rien de cassé de façon irréversible.

```bash
curl http://localhost:8086/q/health/live
curl http://localhost:8086/q/health/ready

```

![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/2026/08/Capture-d---e--cran-2026-08-22-a---20.36.26.png)

![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/2026/08/Capture-d---e--cran-2026-08-22-a---20.36.49.png)

Si en plus on fait céder la charpente (`POST /taverne/incendie/effondrements`), la liveness bascule aussi, et là il n'y a plus de discussion possible : l'instance doit être remplacée.  
C'est la seule branche du runbook, plus loin dans l'article, qui commence par "redémarrer" plutôt que par "diagnostiquer".

Le feu couve, le service continue tant bien que mal, jusqu'à ce qu'un signal vienne de l'extérieur : il faut fermer.

## Fermer la taverne sans perdre personne

Un `SIGTERM`, c'est un messager qui frappe à la porte pour annoncer la fermeture immédiate. On n'a pas le temps de finir de vider la salle, seulement celui de laisser partir ceux qui sont déjà attablés.

Les requêtes HTTP en cours, Quarkus s'en occupe tout seul : il arrête d'accepter de nouvelles connexions et laisse les tournées en cours se terminer, dans la limite de `quarkus.shutdown.timeout`.  
`SalleCommuneResource` sert justement des tournées volontairement lentes pour le vérifier :

```bash
curl "http://localhost:8086/taverne/salle/tournees?secondes=15" &
kill -TERM $(lsof -i :8086 -sTCP:LISTEN -t)

```

> Un piège à connaître si vous testez ça vous-même : en mode `quarkus:dev`, ce mécanisme ne tient pas sa promesse, l'application se termine quasi instantanément malgré la requête en vol.

Ce que Quarkus ne surveille pas, en revanche, ce sont les plis encore dans les buffers de la volière.   
Le serveur HTTP n'a jamais eu connaissance de ces messages, donc il n'a aucune raison de les attendre. `ArretGracieuxObserver` intercepte l'événement d'arrêt pour vidanger ce qui reste, avec son propre délai, configurable via `taverne.voliere.vidange-max` (10 secondes par défaut) :

```java
void aLArret(@Observes ShutdownEvent evenement) {
    long plisPerdus = voliereService.attendreVidange(delaiVidange);
    if (plisPerdus > 0) {
        LOG.warnf("La taverne ferme avec %d plis non lus", plisPerdus);
    }
}

```

C'est un point que je trouve sous-documenté en général : un arrêt gracieux bien réglé ne protège que ce que le framework connaît.   
Tout canal applicatif, toute file interne, tout buffer maison a besoin de son propre observateur de `ShutdownEvent` s'il doit survivre au signal d'arrêt.

```log
10:31:39,936 INFO  [fr.el.ta.fl.ar.SalleCommuneService] (executor-thread-1) Debut de service : aventurier=aventurier anonyme, duree=15s, tourneesEnCours=1
10:31:42,885 INFO  [io.qu.ve.ht.ru.fi.GracefulShutdownFilter] (main) Waiting for HTTP requests to complete
10:31:54,941 INFO  [fr.el.ta.fl.ar.SalleCommuneService] (executor-thread-1) Tournee servie jusqu'au bout : aventurier=aventurier anonyme
10:31:54,983 INFO  [io.qu.ve.ht.ru.fi.GracefulShutdownFilter] (executor-thread-1) All HTTP requests complete
10:31:54,993 INFO  [fr.el.ta.fl.ar.ArretGracieuxObserver] (main) Fermeture des portes : tourneesEnCours=0, corbeauxEnVol=0, delaiAccorde=30s                                                              
10:31:54,993 INFO  [fr.el.ta.fl.co.VoliereService] (main) Vidange terminee : tous les plis recuperes ont ete lus                                                                                          
10:31:54,993 INFO  [fr.el.ta.fl.ar.ArretGracieuxObserver] (main) Salle vide et voliere vidangee : la taverne peut fermer sereinement                                                                      
10:31:55,010 INFO  [io.quarkus] (main) la-taverne-en-flammes stopped in 15.132s       
```

La salle se vide, mais deux comptoirs restent ouverts encore un peu : la cuisine, qui tente de sortir les derniers plats, et le grimoire, qu'on continue de consulter au cas où.

## La cuisine et le grimoire : deux façons de border une attente

Deux comptoirs, deux façons de gérer une attente qui traîne, et deux styles de code pour montrer qu'il n'y a pas une seule bonne manière de faire.

### La cuisine réactive

[En cuisine, le cuisinier ne peut pas laisser un aventurier planté devant une assiette vide indéfiniment](https://www.sfeir.dev/back/le-tavernier-aux-huit-bras-la-programmation-reactive-vue-depuis-le-comptoir/). Le code utilise Mutiny et un timeout posé directement dans la chaîne, avec un `taverne.cuisine.timeout` réglable (2 secondes par défaut) :

```java
return preparerPlatAsynchrone(platDemande, dureePreparationMs)
    .ifNoItem().after(timeoutCuisine)
    .failWith(() -> new TimeoutException("La cuisine est surchargee !"))
    .onFailure().recoverWithItem(() -> Repas.secours(platDemande));

```

Passé le délai, la chaîne échoue puis se rattrape immédiatement sur un `Repas` de secours plutôt que de renvoyer une erreur à l'appelant.

```bash
curl "http://localhost:8086/taverne/cuisine/commandes?plat=ragout&preparationMs=3000"

```

![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/2026/08/image-14.png)

### Le grimoire déclaratif

Au même moment, le tavernier consulte le grimoire de la guilde pour retrouver une recette, une ressource qui vit à l'autre bout du royaume et qui peut très bien ne pas répondre. [Ici, le code passe par MicroProfile Fault Tolerance](https://www.sfeir.dev/back/la-taverne-sous-controle-maitriser-les-flux-avec-quarkus/), en déclaratif : `@Timeout`, `@Retry` et `@Fallback` posés en annotations sur `GrimoireService.recupererRecette`, avec une tentative de plus avant d'abandonner.

```java
@Timeout(value = 1500, unit = ChronoUnit.MILLIS)
@Retry(maxRetries = 1, delay = 100, delayUnit = ChronoUnit.MILLIS)
@Fallback(fallbackMethod = "recetteDeSecours")
public Recette recupererRecette(String nom) { ... }

```

Le style déclaratif se lit plus vite et se règle par configuration externe sans toucher au code (`GrimoireService/recupererRecette/Timeout/value`, par exemple). Le style réactif de la cuisine donne en échange plus de contrôle sur ce qui se passe exactement à l'échéance du délai, utile quand le comportement de repli dépend d'un état qu'une simple annotation ne peut pas exprimer.

```bash
curl -X PUT "http://localhost:8086/taverne/grimoire/pannes?active=true"
curl "http://localhost:8086/taverne/grimoire/recettes?nom=tourte"

```

![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/2026/08/Capture-d---e--cran-2026-08-24-a---12.40.01.png)

Dans les deux cas, le résultat visible côté client est le même : jamais d'erreur 500 brute, toujours quelque chose à servir.

Pendant que la cuisine et le grimoire tiennent bon, un troisième problème s'accumule sans bruit, loin au-dessus des têtes : la volière.

## La volière : un consumer lag qu'on voit à l'œil nu

Les corbeaux continuent de partir livrer les commandes, mais personne au colombier ne les lit assez vite.   
Le canal `corbeaux-en-vol` est in-VM, donc exécutable sans broker, mais la mécanique est la même qu'avec le connecteur Kafka de SmallRye Reactive Messaging. `ColombierListener` lit les plis un par un, volontairement lentement (`taverne.voliere.traitement-ms`, 200 millisecondes par défaut), ce qui laisse un retard s'accumuler pendant qu'on lâche des corbeaux plus vite qu'on ne les traite.

```bash
curl -X POST "http://localhost:8086/taverne/voliere/lachers?nombre=40"
curl http://localhost:8086/taverne/voliere

```

Le champ `corbeauxEnVol` de la réponse est l'équivalent local d'un lag Kafka. On peut le regarder grimper en temps réel en enchaînant les appels, puis regarder la vidange à l'arrêt le faire redescendre à zéro, ou pas, si le délai accordé est trop court pour le volume accumulé.   
C'est d'ailleurs le seul endroit de la démo où on peut délibérément casser la promesse de résilience, en réglant `taverne.voliere.vidange-max` trop bas par rapport à `taverne.voliere.traitement-ms` et au nombre de corbeaux lâchés juste avant l'arrêt.

```log
12:44:04,928 WARN  [fr.el.ta.fl.co.ColombierListener] (executor-thread-2) Lecture des plis interrompue : le corbeau sera relu au prochain demarrage
12:44:04,930 INFO  [fr.el.ta.fl.ar.ArretGracieuxObserver] (Shutdown thread) Fermeture des portes : tourneesEnCours=0, corbeauxEnVol=194, delaiAccorde=30s
12:44:14,932 WARN  [fr.el.ta.fl.co.VoliereService] (Shutdown thread) Vidange incomplete : 145 plis perdus faute de temps
12:44:14,932 WARN  [fr.el.ta.fl.ar.ArretGracieuxObserver] (Shutdown thread) La taverne ferme avec 145 plis non lus : allonger taverne.voliere.vidange-max ou accelerer le traitement
```

Un dernier endroit de la taverne ne peut vraiment rien se permettre de perdre, quoi qu'il arrive : le comptoir du grand livre.

## Le grand livre : ce qu'on ne peut pas laisser brûler

Trois scénarios sur `GrandLivreService`, tous protégés par `@Transactional`, chacun rejouant une façon différente pour l'incendie de menacer le seul registre que la taverne ne peut pas se permettre de perdre.

### L'écriture atomique

[Le scénario nominal écrit deux lignes dans la même transaction](https://www.sfeir.dev/back/la-taverne-panache-persister-les-recettes-avec-quarkus/), la consommation et la taxe de guilde. Les deux sont commitées ensemble ou pas du tout.

```bash
curl -X POST "http://localhost:8086/taverne/grand-livre/ecritures?aventurier=Grimgor&montant=30"

```

```json
[
  {
    "id": 1,
    "aventurier": "Grimgor",
    "libelle": "Tournee de biere",
    "montantPiecesOr": 30,
    "enregistreLe": "2026-08-24T16:02:53.926644Z"
  },
  {
    "id": 2,
    "aventurier": "Grimgor",
    "libelle": "Taxe de la guilde",
    "montantPiecesOr": 3,
    "enregistreLe": "2026-08-24T16:02:53.976498Z"
  }
]
```

### L'écriture interrompue

Une poutre en flammes tombe entre les deux écritures : JTA annule tout, aucune ligne ne reste, le grand livre garde un état cohérent même si l'écriture visible par l'appelant échoue.

```bash
curl -X POST "http://localhost:8086/taverne/grand-livre/ecritures-interrompues?aventurier=Grimgor"

```

[L'exception métier remonte telle quelle jusqu'au \`GlobalExceptionMapper\`](https://www.sfeir.dev/back/cartographier-les-pieges-dun-donjon-industrialiser-la-gestion-des-erreurs-avec-quarkus/), qui la traduit en RFC 7807 avec un statut 500 : c'est une erreur interne classique, pas une histoire de timeout.

```log
18:04:23,072 ERROR [fr.el.ta.fl.re.er.GlobalExceptionMapper] (executor-thread-1) Echec interne pendant l'incendie: java.lang.IllegalStateException: Une poutre en flammes emporte le grand livre avant la fin de l'ecriture
```

```json
{
  "type": "https://tavern.eletutour.fr/problems/internal-error",
  "title": "Erreur interne",
  "status": 500,
  "detail": "Une poutre en flammes emporte le grand livre avant la fin de l'ecriture",
  "instance": "/taverne/grand-livre/ecritures-interrompues"
}
```

### L'écriture lente

Le troisième scénario simule une base ralentie, comme si la chaleur de l'incendie remontait jusqu'à la cave où sont rangés les registres.   
Un `@TransactionConfiguration(timeout = 2)` coupe court plutôt que de garder des verrous SQL indéfiniment, en dessous du timeout global par défaut de Narayana.

```bash
curl -X POST "http://localhost:8086/taverne/grand-livre/ecritures-lentes?attenteMs=5000"

```

Cette fois l'erreur remonte en 503 : la transaction a été annulée par le reaper Narayana, c'est attendu et temporaire, pas une panne.   
Le piège technique, si vous creusez le sujet : le reaper travaille depuis un thread de surveillance séparé, donc l'exception qui remonte à l'appelant est enveloppée, généralement dans une `ArcUndeclaredThrowableException` qui porte elle-même une `RollbackException`.   
Il faut parcourir la chaîne de causes pour la reconnaître, pas juste vérifier le type de l'exception de premier niveau.

```java
private boolean estAnnulationDeTransaction(Throwable exception) {
    for (Throwable cause = exception; cause != null; cause = cause.getCause()) {
        if (cause instanceof RollbackException || cause instanceof TransactionalException) {
            return true;
        }
        if (cause.getCause() == cause) {
            break;
        }
    }
    return false;
}

```

```log
18:07:57,998 WARN  [co.ar.at.arjuna] (Transaction Reaper) ARJUNA012117: TransactionReaper::check processing TX 0:ffffc0a80142:f055:6a8c6b2d:8 in state  RUN                                               
18:07:58,003 WARN  [co.ar.at.arjuna] (Transaction Reaper Worker 0) ARJUNA012095: Abort of action id 0:ffffc0a80142:f055:6a8c6b2d:8 invoked while multiple threads active within it.                       
18:07:58,004 WARN  [co.ar.at.arjuna] (Transaction Reaper Worker 0) ARJUNA012381: Action id 0:ffffc0a80142:f055:6a8c6b2d:8 completed with multiple threads - thread executor-thread-1 was in progress with java.base/java.lang.Thread.sleepNanos0(Native Method)                                  
[...]                                                                                                                                                                                                       
18:07:58,005 WARN  [co.ar.at.arjuna] (Transaction Reaper Worker 0) ARJUNA012108: CheckedAction::check - atomic action 0:ffffc0a80142:f055:6a8c6b2d:8 aborting with 1 threads active!                      
18:07:58,006 WARN  [or.hi.or.jta] (Transaction Reaper Worker 0) HHH90007020: Transaction afterCompletion called by a background thread; delaying afterCompletion processing until the original thread can handle it. [status=4]                                                                                                                                                                                     
18:07:58,006 WARN  [co.ar.at.arjuna] (Transaction Reaper Worker 0) ARJUNA012121: TransactionReaper::doCancellations worker Thread[#61,Transaction Reaper Worker 0,5,main] successfully canceled TX 0:ffffc0a80142:f055:6a8c6b2d:8                                                                                                                                                                                   
18:08:01,000 WARN  [co.ar.at.arjuna] (executor-thread-1) ARJUNA012077: Abort called on already aborted atomic action 0:ffffc0a80142:f055:6a8c6b2d:8                                                       
18:08:01,009 WARN  [fr.el.ta.fl.re.er.GlobalExceptionMapper] (executor-thread-1) Transaction annulee par le gestionnaire JTA : Error invoking subclass method  
```

```json
{
  "type": "https://tavern.eletutour.fr/problems/transaction-rollback",
  "title": "Transaction annulee",
  "status": 503,
  "detail": "La transaction a depasse son timeout, aucune ecriture n'a ete conservee",
  "instance": "/taverne/grand-livre/ecritures-lentes"
}
```

Le feu finit par être maîtrisé, ou pas. Dans les deux cas, quelqu'un doit reprendre les événements de la nuit et en tirer des gestes concrets.

## Le lendemain : runbook et post-mortem

`RunbookService` reprend le rôle du tavernier de garde, celui qu'on réveille au milieu de la nuit et qui doit décider, sans réfléchir longtemps, par quelle porte commencer.   
Il lit les sondes, puis descend vers la dépendance qui bloque, toujours dans le même ordre. Liveness d'abord (faut-il redémarrer ?), readiness ensuite (que dit la sonde de readiness ?), puis le retard de la volière, puis le grimoire, puis une lenteur résiduelle si tout le reste est vert.

```bash
curl http://localhost:8086/taverne/exploitation/runbook

```

Le diagnostic renvoyé porte la branche retenue en toutes lettres (`DOWN/Liveness`, `DOWN/Readiness`, `UP mais retard de messages`, etc.), avec la liste des gestes à faire dans l'ordre.   
L'idée est que le tavernier de garde, pressé, n'ait pas à relire le code pour savoir par où commencer.

```json
{
  "liveness": "UP",
  "readiness": "UP",
  "branche": "UP",
  "tourneesEnCours": 0,
  "voliere": {
    "corbeauxLaches": 0,
    "corbeauxTraites": 0,
    "corbeauxEnVol": 0
  },
  "lignesGrandLivre": 2,
  "latenceGrimoireMs": 50,
  "grimoireEnPanne": false,
  "actions": [
    "Rien a signaler : la taverne sert normalement"
  ],
  "etabliLe": "2026-08-24T16:20:58.653388Z"
}
```

avant que tout s'enflamme

```json
{
  "liveness": "UP",
  "readiness": "DOWN",
  "branche": "DOWN/Readiness",
  "tourneesEnCours": 0,
  "voliere": {
    "corbeauxLaches": 0,
    "corbeauxTraites": 0,
    "corbeauxEnVol": 0
  },
  "lignesGrandLivre": 2,
  "latenceGrimoireMs": 50,
  "grimoireEnPanne": false,
  "actions": [
    "Verifier la dependance en cause via GET /q/health/ready",
    "Inspecter le pool de connexions Agroal (vendor_agroal_active_count sur /q/metrics)",
    "Controler le retard de la voliere (equivalent du consumer lag Kafka)",
    "Une fois la cause traitee : POST /taverne/incendie/extinctions"
  ],
  "etabliLe": "2026-08-24T16:24:59.213999Z"
}
```

mais dès que ça commence...

Le post-mortem, lui, n'invente rien : il agrège ce que les autres services ont réellement enregistré pendant l'incident (chronologie, plats servis, repas de secours, plis en attente, écritures préservées), sans jugement sur qui a fait quoi.   
Ce sans-blâme n'est pas une posture éditoriale, c'est une contrainte de conception : le document ne peut littéralement pas contenir autre chose que des faits mesurés.

```json
{
  "chronologie": [
    {
      "horodatage": "2026-08-24T16:24:55.795745Z",
      "etape": "DEBUT_INCENDIE",
      "detail": "Le feu prend : friture de la cuisine"
    },
    {
      "horodatage": "2026-08-24T16:24:55.795831Z",
      "etape": "TOCSIN",
      "detail": "La cloche sonne, la readiness passe DOWN, l'orchestrateur retire l'instance du routage"
    }
  ],
  "impact": {
    "platsServis": 0,
    "repasDeSecours": 0,
    "corbeauxEnAttente": 300,
    "ecrituresPreservees": 2
  },
  "causeRacine": "Incendie toujours en cours, origine relevee : friture de la cuisine",
  "ceQuiAFonctionne": [
    "Les sondes de readiness ont sorti l'instance du routage sans intervention humaine",
    "La voliere a fini de traiter 100 plis deja recuperes",
    "Le grand livre conserve 2 ecritures completes : aucune tournee facturee a moitie"
  ],
  "actionsCorrectives": [
    "Traiter l'origine de l'incendie avant de remettre l'instance dans le routage",
    "Ajouter des consumers ou des partitions : 300 plis etaient encore en vol",
    "Revoir quarkus.shutdown.timeout au regard de la duree reelle des requetes longues",
    "Ajouter un rate limiting sur les commandes HTTP pour proteger la cuisine",
    "Verifier que chaque appel sortant est borne par un @Timeout et un @Fallback"
  ]
}
```

Une fois le calme revenu, rien n'empêche de rallumer le feu pour vérifier qu'on a bien tout compris.

## Conclusion

Le tavernier de minuit n'existe pas, mais les décisions qu'il doit prendre, si.   
Aucun des sept mécanismes présentés ici n'est propre à une taverne fictive.   
L'arrêt gracieux, les sondes de santé, les timeouts posés sur chaque appel sortant, la vidange des files internes, les transactions bornées dans le temps, un runbook qui suit toujours le même chemin de décision : ce sont les questions que pose n'importe quelle application qui tourne en production, dès qu'un orchestrateur peut la redémarrer ou qu'une dépendance peut répondre en retard.

Ce qui change, c'est le coût pour se les poser.   
Pas besoin d'un cluster Kubernetes, d'un vrai broker Kafka ou d'une base de données sous charge pour observer une readiness passer DOWN, un consumer lag grimper ou une transaction se faire annuler par un reaper.   
Une JVM en local et quelques appels `curl` suffisent à provoquer chaque panne à la demande, autant de fois que nécessaire, et à vérifier que le filet de sécurité tient bien la charge qu'on lui a promise.

Pour ceux ayant lu mes [articles Spring Boot sur la résilience applicative avec Chaos Monkey](https://www.sfeir.dev/back/application-a-toute-epreuve-transformez-votre-application-en-forteresse-de-resilience/) : une telle librairie n'existe **pas encore** dans l'univers Quarkus, ce qui explique le chaos codé à la main plutôt qu'injecté par une dépendance tierce. Le "pas encore" n'est pas anodin.

---

Le dépôt contient de quoi rejouer chaque scénario indépendamment : chaque ressource a son endpoint de réinitialisation (`DELETE /taverne/incendie`, `DELETE /taverne/voliere`, `DELETE /taverne/grand-livre`), pour repartir d'un état propre sans redémarrer la JVM. 

[GitHub - ErwanLT/quarkus-demo: Demo project for quarkus possibilityDemo project for quarkus possibility. Contribute to ErwanLT/quarkus-demo development by creating an account on GitHub.![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/icon/favicon-980123e5-e1bc-4004-9606-16cb9e21cd8b.png)GitHubErwanLT![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/thumbnail/5635256a-85fe-4dc6-8c3a-7e4df754b269-3d2ec454-4c43-4d01-b5e0-3c24e4b324c8)](https://github.com/ErwanLT/quarkus-demo?ref=sfeir.dev)