Aller au contenu

Comment avance une exécution ​

Une exécution démarre à Début, suit les fils de nœud en nœud et est terminée quand chaque branche a fini et que Fin a été atteint. Cette page explique les règles qu’elle suit ; ce que fait chaque nœud est dans la référence des nœuds, et les valeurs qui voyagent avec elle dans données.

Début et Fin ​

Une expérience a exactement un Début et une Fin.

  • Début n’a pas d’entrée. Il passe aussitôt, et sa ligne dans la chronologie donne la graine de l’exécution. Sa sortie peut avoir plusieurs fils : l’expérience commence alors par des branches parallèles.
  • Chaque branche qui atteint Fin s’y arrête. End s’affiche comme en cours dès la première arrivée et passe une fois, après que la dernière branche a fini — et pas du tout si une étape a échoué. C’est ce passage qui rend l’exécution Réussi.
  • Une exécution où chaque branche a fini sans erreur mais aucune n’a atteint End échoue avec run.no_end.

Sorties et fils ​

L’étape d’un nœud se termine en choisissant une sortie, et l’exécution suit chaque fil de cette sortie. La plupart des nœuds ont une seule sortie, Sortie ; certains choisissent entre plusieurs :

NœudSorties qui doivent être reliéesSorties qui peuvent être reliées
Fin——
Branche parallèleBranche 1, Branche 2—
Branche sur statut, Branche sur valeurOui, Non—
Chaque attente (Attente OSC, Attente UDP, Attente MQTT, Attente de requête HTTP, Attente WebSocket)ReçuExpiré
BoucleCorps, TerminéLimite
Tout autre nœudSortie—

Pour relier, faites glisser d’une sortie vers un nœud ; déposée sur un canevas vide, elle ajoute un nouveau nœud à cet endroit. Faire glisser depuis une sortie qui a déjà un fil en ajoute un autre. Ajouter à la suite, la touche A et le + sur un fil insèrent un nœud dans le fil existant à la place.

Un graphe inachevé est un brouillon : il s’enregistre, mais il ne s’exécute pas. Complétez le graphe dans la barre d’outils dit ce qui manque et montre le nœud. Voir ce qui est vérifié avant une exécution.

Branches parallèles ​

Plusieurs fils depuis une sortie ​

Quand une sortie a plusieurs fils — celui de Début compris — chaque nœud vers lequel ils mènent s’exécute en même temps. Le premier fil poursuit la branche ; chaque fil supplémentaire démarre une branche parallèle. Chaque branche porte sa propre copie des variables et de la dernière réponse HTTP, si bien que ce qu’une branche définit ou reçoit n’est pas vu par les autres.

Branche parallèle et Join ​

Branche parallèle passe aussitôt et sort par les deux Branche 1 et Branche 2 — la même chose que deux fils depuis une sortie, dessiné comme un nœud.

Jonction de branches attend chaque fil qui y mène, puis continue comme une seule branche avec les copies fusionnées dans l’ordre de ces fils :

  • les variables de tous — sur un nom que deux branches définissent toutes deux, le fil listé plus tard dans l’expérience l’emporte ;
  • la réponse HTTP du dernier fil, dans cet ordre, qui en apporte une ;
  • pour les attentes après lui, la plus ancienne de leurs dernières actions.

L’ordre des fils décide, jamais la branche qui s’est trouvée finir en premier.

Ne joignez que ce qui s’exécute en parallèle

Un Join compte ses fils, quelle que soit la façon dont ils en sont venus à s’exécuter en parallèle : depuis un Branche parallèle, depuis plusieurs fils d’une sortie, depuis des chemins séparés. Derrière le Oui et le Non d’une branche, un seul chemin s’exécute, donc un Join alimenté par les deux attend une branche qui n’arrive jamais : l’exécution échoue avec run.join_waiting, en nommant combien de fils n’ont jamais été suivis. Pour réunir des chemins alternatifs, reliez-les directement au nœud suivant.

Un nœud qui n’est pas un Join, atteint par deux branches parallèles, s’exécute une fois pour chacune d’elles.

Quand une étape échoue ​

Le premier échec fait échouer l’exécution. Les autres branches ne démarrent aucune nouvelle étape : une répétition ou une charge se termine tôt, toute autre étape où elles se trouvent va jusqu’à sa fin. Un échec qu’elles rencontrent entre-temps est signalé dans la chronologie mais n’est pas l’erreur de l’exécution. Une étape qui a rencontré un délai d’attente alors qu’un fil Expiré était là n’a pas échoué — voir attentes.

Branchement ​

NœudSort par Oui quand
Branche sur statutla dernière réponse HTTP sur ce chemin a le statut donné
Branche sur valeursa comparaison tient — voir comparer des valeurs

Sinon, chacun sort par Non. Un branchement sur statut a besoin d’une requête HTTP avant lui sur chaque chemin ; un branchement sur valeur a besoin que les noms qu’il lit soient connus là. Quand les chemins après Oui et Non se rejoignent, le nœud où ils se rejoignent s’exécute une fois, et seules les variables définies sur les deux chemins y sont connues (où une variable est connue).

Réessai ​

Une étape qui envoie ou écoute peut réessayer quand elle échoue : activez réessayer en cas d’échec dans ses propriétés.

RéglageQuoiPlageValeur initiale
Tentativestentatives au total, la première comprise1–103
Pause, msla pause avant la deuxième tentative0–60 000 ms500
Pausesidentiques : chaque pause identique ; qui doublent : chaque pause deux fois la précédente—identiques
  • Le réessai s’applique à Requête HTTP, Message TCP, Publication MQTT, Message OSC, Datagramme UDP, Connexion WebSocket, Envoi WebSocket et chaque attente. Les autres nœuds le refusent (node.retry_unsupported), et une requête HTTP sous charge ne prend pas de réessai.
  • Aucune pause n’est plus longue que 60 s, quoi que donne le doublement.
  • Chaque tentative échouée apparaît dans la chronologie comme Réessai, avec son numéro et sa raison. L’étape passe ensuite, ou échoue avec la raison de la dernière tentative.
  • Seule l’exécution est répétée. Un champ dont le modèle ne se résout pas échoue aussitôt.
  • Un envoi qui attend sa réponse envoie de nouveau. Une attente attend de nouveau, en comptant depuis la dernière action de la branche comme avant.
  • Une attente avec un fil Expiré n’échoue pas sur un délai d’attente, donc elle n’est pas réessayée : elle suit Expiré.
  • Stop met fin à une pause aussitôt.

Répétition ​

Une étape qui envoie peut envoyer encore et encore — un battement, une interrogation, un flux régulier — sans boucle dans le graphe : activez répéter l’envoi.

RéglageQuoiPlageValeur initiale
Répéterun nombre de fois ou pendant une durée—un nombre de fois
Foisenvois au total, le premier compris2–10 00010
Pendant, mscombien de temps continuer d’envoyer, depuis le premier envoi1–300 000 ms10 000
Toutes les, msla pause entre deux envois10–60 000 ms1000
Gigue, mschaque pause est plus longue de ce montant au plus, au hasard0–60 000 ms0
  • La répétition s’applique à Requête HTTP, Message TCP, Publication MQTT, Message OSC, Datagramme UDP et Envoi WebSocket (node.repeat_unsupported ailleurs). Une requête HTTP a soit la répétition, soit la charge, pas les deux.
  • Chaque envoi est fait comme un seul le serait : ses modèles sont relus — {{counter}} est le numéro de l’envoi, {{now}} son heure — et le réessai, quand il est actif, s’applique à chaque envoi. Un envoi qui attend une réponse attend la sienne.
  • Pour une durée, un envoi n’est fait que s’il peut démarrer avant la fin du temps.
  • La gigue est tirée de la graine de l’exécution : la même graine donne les mêmes pauses.
  • La chronologie signale la progression comme Répétition au plus une fois par seconde. L’étape passe après le dernier envoi, avec le résultat de cet envoi ; un envoi qui échoue définitivement fait échouer l’étape.
  • Un échec sur une autre branche met fin aux envois ; Stop met fin à une pause aussitôt.

Elle doit tenir dans une exécution : les envois et leurs plus longues pauses ((count − 1) × (interval + jitter)) 300 s au plus (node.repeat_too_long), et une répétition minutée 10 000 envois au plus (node.repeat_too_many).

Boucle ​

Boucle exécute les étapes de sa sortie Corps encore et encore ; la dernière d’entre elles est reliée en retour à la Boucle.

RéglageQuoiPlage
Itérations au plusle plus grand nombre d’itérations1–1000
arrêter plus tôt quandune condition de sortie : Valeur, Condition, Attendu, comme dans Vérifier une valeurfacultatif
  1. Atteinte depuis l’extérieur, la Boucle démarre l’itération 1 sur Corps.
  2. Chaque fois que le corps revient, la condition de sortie est lue — après l’itération, donc le corps s’exécute toujours au moins une fois et peut définir ce qu’il teste.
  3. Quand la condition tient, la Boucle sort par Terminé.
  4. Sinon, l’itération suivante démarre, tant qu’il en reste.
  5. Quand les itérations s’épuisent d’abord, la Boucle sort par Limite s’il est relié, et fait échouer l’exécution avec loop.limit s’il ne l’est pas. Sans condition, le corps s’exécute à chaque itération et la Boucle sort par Terminé.

À l’intérieur du corps, {{counter}} est le numéro de l’itération, puisque chaque nœud compte ses propres exécutions. La condition et les étapes après Terminé ou Limite peuvent utiliser ce que chaque itération du corps définit — un statut que le corps extrait, par exemple ; le corps lui-même ne voit que ce qui était connu quand la Boucle a été atteinte.

Le modèle Interroger jusqu’à « ready » demande son statut à un appareil toutes les 0,3 s jusqu’à ce qu’il réponde ready, 10 fois au plus.

Ce qu’un corps peut contenir ​

Un corps s’exécute comme une seule branche, une itération après l’autre. Le fil qui revient à la Boucle est le seul cycle qu’une expérience peut avoir ; tout autre est graph.cycle.

RègleErreur
Quelque chose sur Corps revient à la Boucleloop.no_return
Chaque sortie du corps a un seul filloop.body_parallel
Chaque sortie du corps continue dans le corps ou revient à la Boucleloop.body_leaves
Seule la sortie Corps de la Boucle mène dans le corpsloop.body_entered
Aucun Début, Fin, Branche parallèle, Jonction de branches ni autre Boucle dans le corpsloop.body_unsupported

Attentes ​

Une attente passe quand un message qu’elle attend arrive : Attente OSC, Attente UDP, Attente MQTT, Attente de requête HTTP et Attente WebSocket. Ce que chacun prend est dans la référence des nœuds ; voici comment ils écoutent.

Écouter dès le début ​

L’exécution ouvre ce sur quoi ses attentes écoutent avant sa première étape, pour qu’une réponse plus rapide que l’étape suivante ne soit pas manquée :

AttenteOuvert avant la première étape
OSC, UDPun socket UDP par adresse Écouter sur (IP:port), partagé par chaque attente dessus
Requête HTTPun écouteur par adresse — l’émulateur HTTP de l’exécution quand il y en a un, sinon un qui répond 204
MQTTune connexion par broker et filtre de topic, abonnée ; les messages retenus que le broker rejoue alors sont ignorés
WebSocketrien : elle lit la connexion qu’un Connexion WebSocket a ouverte quand il s’est exécuté

Parce qu’ils s’ouvrent en premier, ces adresses sont fixées avant l’exécution : une attente OSC, UDP ou HTTP écoute sur un IP:port littéral avec un port différent de 0, et le broker et le topic d’une attente MQTT n’acceptent que des paramètres. Un port qui ne peut pas être ouvert — pris, ou qui n’est pas une adresse de cet ordinateur — arrête l’exécution avant tout trafic, au champ de cette attente. Tout est fermé quand l’exécution se termine, de quelque façon que ce soit.

Quels messages comptent ​

Une attente considère les messages arrivés après que la dernière action sur sa branche a démarré — la dernière requête, le dernier message, la dernière publication, la dernière connexion WebSocket ou le dernier envoi — ou, avant toute action, après le démarrage de l’exécution. Un message d’avant la requête ne compte pas, et un délai ou un journal entre la requête et l’attente ne cache pas sa réponse. Après un Join, la plus ancienne des dernières actions des branches fusionnées compte.

Une attente prend le premier message qui correspond et le consomme : deux attentes ne prennent jamais le même message.

Chaque socket, abonnement ou connexion conserve au plus 1024 messages et 64 Mio pour ses attentes ; au-delà, les plus anciens sont abandonnés et comptés.

Délai d’attente ​

Délai d’attente, ms vaut 1–120 000 ms, 2000 au départ. Quand rien ne correspond à temps :

  • avec un fil Expiré, l’attente le suit ;
  • sans, l’étape échoue avec wait.timeout, qui dit combien d’autres messages sont arrivés entre-temps — un mauvais motif a l’air différent d’un appareil silencieux — et, dans son détail, combien de messages plus anciens ont été abandonnés quand la file était pleine.

La variable de l’attente — reply, ou request pour HTTP — n’existe qu’après Reçu. Quand l’Inspecteur capture, l’étape relie aussi la trame qu’elle a prise : voir la chronologie.

Une réponse à la même étape ​

Un Message OSC ou un Datagramme UDP peut attendre sa propre réponse : activez attendre une réponse.

RéglageQuoiValeur initiale
Réponse sur (IP:port)l’adresse sur laquelle la réponse est attendue ; le port 0 signifie n’importe quel port libre0.0.0.0:0
Motif d’adresse de réponse (OSC), Charge utile de réponse (UDP)ce que la réponse doit être, comme dans l’attente correspondanten’importe quoi
Délai d’attente, ms1–120 000 ms2000
Variable de réponsela variable dans laquelle la réponse est écritereply

Le socket sur Réponse sur (IP:port) est ouvert avant la première étape, comme celui d’une attente, et le message part de lui : un appareil qui répond au port même de l’expéditeur est entendu, et un appareil qui répond à un port fixe est entendu quand ce port est celui donné. L’étape passe avec une réponse qui correspond, et la variable existe après sa sortie. Il n’y a pas de sortie Expiré : aucune réponse à temps fait échouer l’étape, et le réessai peut envoyer de nouveau. Pour brancher sur un silence, utilisez une attente séparée.

Ce qui est vérifié avant une exécution ​

L’éditeur vérifie l’expérience au fur et à mesure que vous la modifiez ; le bouton Exécuter la vérifie une fois de plus. Un problème nomme le nœud, et le champ quand il y en a un.

RègleErreur
L’expérience a un nomdoc.name_required
1–64 nœuds, exactement un Début et une Findoc.node_count, doc.start_end_count
Le Début n’a pas d’entréegraph.start_input
Un fil mène à un autre nœud qui existedoc.connection_invalid
Le même fil n’est pas là deux foisdoc.connection_duplicate
Chaque sortie qui doit être reliée l’estgraph.outputs_required
Un nœud n’a pas de fil sur une sortie qu’il n’a pasgraph.port_unexpected
Chaque nœud peut être atteint depuis le Débutgraph.unreachable
Aucun cycle sauf le fil d’une Boucle qui revientgraph.cycle, et les règles du corps
Une vérification ou un Extract a une requête HTTP avant lui sur chaque chemin ; une requête sous charge ne compte pasgraph.needs_http
Chaque modèle s’analyse, et chaque nom qu’il utilise est connu sur chaque chemintemplate.*, name.* — voir données
Chaque champ est présent et dans la plagenode.*
Un nœud qui en nomme un autre — Changer la dégradation, Émulateur en panne/en service, les nœuds WebSocket — en nomme un qui existe, et un nœud WebSocket vient après son connectimpair.relay_unknown, emulator.node_unknown, ws.connection_unknown, ws.connection_after
Deux des sockets de l’exécution ne partagent pas un portvoir défaillances

L’exécution vérifie ensuite ce dont elle a besoin pour démarrer : chaque secret stocké, chaque port ouvert. Tant que tout ne tient pas, aucune étape ne s’exécute et rien n’est envoyé.

Durée limite ​

Une exécution dure au plus 300 s. Une exécution encore en cours est alors arrêtée et échoue avec run.timeout. Depuis la ligne de commande et l’API la limite peut être plus courte, 1–300 s.

Stop ​

Pendant qu’une exécution se déroule, le bouton Exécuter est Arrêter. Stop met fin à l’exécution aussitôt : chaque branche, chaque pause du réessai ou de la répétition, chaque attente et chaque charge — les requêtes en vol sont abandonnées. Ses sockets, abonnements, émulateurs et relais se ferment, et ses connexions WebSocket envoient une trame de fermeture. Tout arrêter dans l’en-tête fait la même chose pour chaque tâche. Une exécution arrêtée n’enregistre aucun rapport ; voir exécutions.