Une app Mule est un ensemble de flows, et un flow est le chemin que suit un Mule event, d’une source jusqu’à la fin. Comprenez bien ces deux idées et le reste de Mule 4 devient beaucoup plus simple : les error handlers, les routers, et même la raison pour laquelle votre payload a disparu après un appel HTTP.
Cette leçon suit une petite app de commandes à travers cinq schémas animés. Chacun s’anime tout seul dès qu’il est à l’écran. Les boutons au-dessus changent l’histoire : faire tomber l’API de stock, changer d’error handler, choisir un router. Mettez-le en pause quand vous voulez et avancez pas à pas avec les flèches.
Une app, plusieurs flows
Une app Mule est livrée sous la forme d’un seul JAR. Les flows vivent dans des fichiers XML sous src/main/mule, à côté d’un pom.xml et d’un mule-artifact.json qui liste ces fichiers. Ce JAR se déploie sur CloudHub 2.0, sur Runtime Fabric ou sur un runtime Mule installé sur vos propres serveurs.
Les flows ne possèdent pas leurs connexions. Un global element, comme une config HTTP Listener ou une config Database, est déclaré une seule fois, et tous les flows de l’app pointent dessus. Tout ce qui change d’un environnement à l’autre va dans un property placeholder comme ${http.port}, pas dans le XML.
L’app de commandes : deux flows, post-order lancé par une requête HTTP et nightly-report lancé par un Scheduler, qui utilisent tous deux des global elements partagés pour le listener HTTP, l’API de stock et la base de données.
Global elements · partagés par tous les flows
- HTTP Listener configport ${http.port}
- HTTP Request configstock-api · ${stock.host}
- Database configorders-db
flow post-order
- HTTP ListenerPOST /orders
- HTTP RequestGET /stock/{sku}
- Loggercommande reçue
flow nightly-report
- Schedulertous les jours à 02:00
- Databasecommandes de la veille
- Loggerligne du rapport
Chaque flow démarre depuis sa propre source. post-order attend une requête, nightly-report attend 02:00. Ils partagent de la configuration, jamais un event.
Ce qui circule, c’est le Mule event
Tout ce que fait un flow, il le fait sur un Mule event. L’event a deux parties : le message, c’est-à-dire un payload plus des attributes, et les variables.
payload, ce sont les données. Pour une requête HTTP, c’est le corps.attributesdisent d’où viennent les données : méthode, chemin, en-têtes, paramètres de requête.varssont à vous. Set Variable les écrit, et elles restent avec l’event pour tout le reste du flow.
Le piège : presque tous les processors renvoient un nouveau message. Appelez une autre API avec HTTP Request et sa réponse devient le payload, son code de statut atterrit dans les attributes, et la commande envoyée par le client a disparu. Sauf si vous avez d’abord gardé ce dont vous avez besoin dans une variable, ou demandé à l’appel de ranger son résultat ailleurs avec target.
Une commande qui traverse post-order : le HTTP Listener transforme la requête en Mule event, Set Variable garde le SKU, et le HTTP Request soit remplace le payload par la réponse du stock, soit, avec target="stock", la range dans vars.stock et laisse le message inchangé.
flow post-order
- HTTP ListenerPOST /orders
- Set Variablesku = #[payload.sku]
- HTTP RequestGET /stock/#[vars.sku]
- Logger#[payload]
Événement Mule
- payload
{ "sku": "SOFA-D5", "qty": 1 }- attributes
method: "POST" requestPath: "/orders" headers: { "content-type": "application/json", … } queryParams: {}- vars
(aucune pour l’instant)
Passez à target="stock" et regardez la ligne du payload. Cette fois, elle ne clignote pas à l’étape HTTP Request : la réponse atterrit dans vars.stock, et la commande est toujours le payload quand le listener répond. Le Logger, dans les deux cas, ne change rien.
Les erreurs prennent un autre chemin
Quand un processor échoue, Mule lève une erreur d’un type comme HTTP:CONNECTIVITY, saute le reste du flow et passe à l’error handler du flow. Le handler exécute le premier On-Error dont le type correspond. Il en existe deux sortes, et elles répondent au client de façon très différente.
- On Error Propagate exécute ses processors, puis relance l’erreur. Le HTTP Listener répond 500 avec la description de l’erreur comme corps. Le payload posé dans le handler n’est pas envoyé, sauf si vous configurez la réponse d’erreur du listener.
- On Error Continue exécute ses processors, puis termine le flow comme un succès. Le listener répond 200 avec le payload, quel qu’il soit.
Et si le flow n’a aucun handler, le handler par défaut de Mule logge l’erreur et la propage.
post-order appelle l’API de stock. Quand l’API est en ligne, le flow se termine par un 200. Quand elle est en panne, le HTTP Request lève HTTP:CONNECTIVITY : avec On Error Propagate, le client reçoit un 500 avec la description de l’erreur ; avec On Error Continue, il reçoit un 200 avec le payload de repli du handler.
flow post-order
- HTTP ListenerPOST /orders
- Set Variablesku
- HTTP RequestGET /stock/#[vars.sku]
- Loggercommande reçue
error handler
- On Error Propagatetype: ANY
- Set Payload{ message: "Stock check failed" }
error handler
- On Error Continuetype: ANY
- Set Payload{ sku: vars.sku, inStock: null }
Événement Mule
- payload
{ "sku": "SOFA-D5", "qty": 1 }- vars
(aucune pour l’instant)
- error
—
Lancez « en panne » avec On Error Continue et regardez le résultat : l’API de stock est en panne et le client reçoit un 200. Parfois, c’est exactement ce que vous voulez : une réponse de repli. Si le client doit savoir que quelque chose a échoué, fixez le code de statut vous-même.
Flow Reference : sub-flow ou flow
Flow Reference appelle un autre flow de la même app avec le même event. Les variables voyagent avec lui, donc le flow appelé peut lire vars.sku, et le payload qu’il laisse derrière lui devient celui de l’appelant au retour. Ce que vous appelez peut prendre deux formes.
- Un sub-flow n’a ni source ni error handler. Mule met ses processors à la place du Flow Reference quand il construit l’app : il fait vraiment partie de l’appelant.
- Un flow sans source peut avoir son propre error handler. Une erreur à l’intérieur va d’abord à ce handler, et n’atteint l’appelant que si le handler la propage.
post-order appelle check-stock avec un Flow Reference. Si check-stock est un sub-flow et que l’appel au stock échoue, c’est l’error handler de post-order qui s’exécute, et le client reçoit un 500. Si check-stock est un flow avec son propre handler On Error Continue, c’est ce handler qui s’exécute, le Flow Reference rend la main normalement et post-order répond 200.
flow post-order
- HTTP ListenerPOST /orders
- Set Variablesku
- Flow Referencecheck-stock
- Loggercommande reçue
sub-flow check-stock · sans source, sans error handler
- HTTP RequestGET /stock/#[vars.sku]
flow check-stock · sans source
- HTTP RequestGET /stock/#[vars.sku]
error handler de check-stock
- On Error Continuetype: ANY
- Set Payload{ sku: vars.sku, inStock: null }
error handler de post-order
- On Error Propagatetype: ANY
Événement Mule
- payload
{ "sku": "SOFA-D5", "qty": 1 }- vars
(aucune pour l’instant)
- error
—
Donc, quand check-stock a son propre On Error Continue, post-order ne voit jamais l’échec. Son Flow Reference rend simplement la main et le Logger s’exécute. Parfait pour un repli, et facile à rater quand vous lisez les logs en vous demandant pourquoi le handler de l’appelant est resté muet.
Routers et scopes changent le chemin
Un flow n’est pas forcément une ligne droite.
- Choice teste ses routes dans l’ordre et exécute la première dont la condition est vraie. Si aucune ne l’est, c’est la route
otherwisequi s’exécute ; elle est facultative. - Scatter-Gather envoie l’event à toutes les routes en même temps, chacune sur son propre thread, et les attend toutes. Le résultat est un seul payload avec une clé par route :
0,1et ainsi de suite. - For Each exécute ses processors une fois par élément d’une collection. Il ne change pas le payload : après la boucle, vous récupérez l’original. Les variables posées dans la boucle restent posées.
Trois flows. Un router Choice envoie une commande vers la route Nantes pour FR, la route New Jersey pour US, et vers un Raise Error dans la route otherwise pour tout autre pays. Un Scatter-Gather appelle l’API de stock et l’API de prix en même temps et renvoie un seul objet aux clés 0 et 1. Un For Each réserve le stock une fois par article de la commande et laisse le payload tel quel : la commande d’origine.
flow route-order
- HTTP ListenerPOST /orders
- Choiceby payload.country
country == "FR"
- HTTP Requestentrepôt de Nantes
country == "US"
- HTTP Requestentrepôt du New Jersey
otherwise
- Raise ErrorAPP:UNSUPPORTED_COUNTRY
- Loggerroutée
flow get-quote
- HTTP ListenerGET /quote/{sku}
- Scatter-Gatherdeux routes
route 0
- HTTP Requeststock API
route 1
- HTTP Requestprice API
- Transform Messagefusionner en un devis
flow reserve-items
- HTTP ListenerPOST /reservations
- For Eachpayload.items
chaque article
- HTTP Requestréserver le stock
- Loggertout est réservé
Événement Mule
- payload
{ "orderId": "A-1042", "country": "FR", "sku": "SOFA-D5" }- vars
(aucune pour l’instant)
Scatter-Gather est le bon réflexe quand deux appels ne dépendent pas l’un de l’autre : le devis attend l’appel le plus lent, pas les deux à la suite. Si une route échoue, Mule attend quand même les autres, puis lève MULE:COMPOSITE_ROUTING, avec à l’intérieur ce qui a échoué et ce qui a marché.
Vérifiez vos acquis
Trois questions sur ce que vous venez de faire tourner. Choisissez une réponse pour en voir l’explication.
Le HTTP Request de post-order a
target="stock". Après son exécution, que contient le payload ?Réponse
La commande envoyée par le client. Avec
target, le résultat de l’appel va dansvars.stocket le message passe sans changer.L’API de stock est en panne, et l’error handler de post-order est un On Error Continue avec un Set Payload. Que reçoit le client ?
Réponse
Un 200 avec le payload du handler. On Error Continue termine le flow comme un succès, donc le listener répond comme si rien n’avait échoué.
post-order appelle check-stock avec un Flow Reference. check-stock est un sub-flow, et l’appel au stock qu’il contient échoue. Quel error handler s’exécute ?
Réponse
Celui de post-order. Un sub-flow n’a pas d’error handler : ses processors s’exécutent à la place du Flow Reference, donc l’erreur va au handler de l’appelant, ou à un scope Try autour du Flow Reference.
D’où viennent les faits
Chaque affirmation de cette leçon a été vérifiée dans la documentation de Mule 4 :
- Développement d’apps Mule et global elements
- Le Mule event et target variables
- Gestion des erreurs, scopes On-Error et la référence du HTTP Listener
- Flows et sub-flows et Flow Reference
- Choice, Scatter-Gather et For Each
- Options de déploiement
C’est la base sur laquelle s’appuie le reste du parcours. Prochaine étape : les watermarks, ou comment un flow de polling se souvient de l’endroit où il s’est arrêté. Si un schéma fait quelque chose que Mule ne ferait pas, dites-le-moi. Les liens de contact sont juste en dessous.
Texte brut: mule-app-flows.md · Tous les parcours