Runtime Resolver
Introduction
Le Runtime Resolver est le moteur central du Workflow Runtime qui traite les variables lors de l'exécution du workflow. Il gère le cycle de vie des variables en enregistrant les outputs, en résolvant les paramètres et en effectuant les castages de types.
Aperçu du Flux d'Exécution
flowchart TD
Start["1. Noeud START<br/>Variables declarees<br/>Dictionnaire initialise"]
Task1["2. TACHE 1 EXECUTER<br/>Produit un output<br/>Exemple: cmd_error_output"]
Register["3. ENREGISTREMENT<br/>Output stocke en dictionnaire<br/>VAR stocke valeur"]
Task2["4. TACHE 2 ATTEND<br/>Contient des parametres<br/>avec variables"]
Resolve["5. RESOLUTION<br/>Scanne parametres pour variables<br/>Remplace par valeurs dictionnaire"]
Cast["6. CASTING<br/>Convertit String vers Type cible<br/>String vers Double, JSON, etc."]
Execute["7. TACHE 2 EXECUTER<br/>Avec valeurs resolues et castees"]
End["8. Noeud END<br/>Dictionnaire persiste"]
Start --> Task1
Task1 --> Register
Register --> Task2
Task2 --> Resolve
Resolve --> Cast
Cast --> Execute
Execute --> End
style Start fill:#e3f2fd
style Task1 fill:#f3e5f5
style Register fill:#fff9c4
style Task2 fill:#f3e5f5
style Resolve fill:#fff9c4
style Cast fill:#fff9c4
style Execute fill:#f3e5f5
style End fill:#c8e6c9
Étape 1 : Déclaration des Variables et Initialisation du Dictionnaire
Au nœud START, les variables sont déclarées et le dictionnaire runtime est initialisé.
{
"Start": [
{
"id": "0",
"variables": [
{
"variableName": "$TIME_OFFSET",
"variableValue": "0",
"is_kpi": false
},
{
"variableName": "$LATITUDE",
"variableValue": "0.0",
"is_kpi": true
},
{
"variableName": "$API_RESPONSE",
"variableValue": "{}",
"is_kpi": false
}
]
}
]
}
Dictionnaire Runtime Initial :
Étape 2 : Exécution de la Tâche et Enregistrement de l'Output
Quand une tâche s'exécute et produit un output, le Runtime Resolver enregistre cet output dans le dictionnaire.
Exemple : Tâche NtpSync
{
"NtpSync": [
{
"id": "1",
"ntp_server": "time.google.com",
"ntp_port": 123,
"ntp_timeout": 5000,
"ntp_offset_output": "$TIME_OFFSET"
}
]
}
Timeline d'Exécution
sequenceDiagram
participant Task as Tache 1<br/>(NtpSync)
participant Resolver as Runtime<br/>Resolver
participant Dict as Dictionnaire<br/>Runtime
Task->>Task: Interroge serveur NTP<br/>time.google.com
Task->>Task: Reçoit réponse temps
Task->>Resolver: Output produit<br/>Offset: '125'
Resolver->>Dict: Enregistre output<br/>$TIME_OFFSET = '125'
Dict->>Dict: Mise à jour dictionnaire
Resolver-->>Task: ✅ Output enregistré
Note over Dict: {<br/> "$TIME_OFFSET": "125",<br/> "$LATITUDE": "0.0",<br/> "$API_RESPONSE": "{}"<br/>}
État du Dictionnaire Après Tâche 1 :
Étape 3 : Résolution des Paramètres
Avant que Tâche 2 s'exécute, le Runtime Resolver scanne tous les paramètres pour identifier les variables (chaînes commençant par $) et les remplace par les valeurs du dictionnaire.
Exemple : Tâche CompareNumber
Processus de Résolution
flowchart LR
Scan["1️⃣ SCANNER<br/>Trouver paramètres<br/>avec variables"]
Identify["2️⃣ IDENTIFIER<br/>num_x: '$TIME_OFFSET'<br/>Contient variable"]
Lookup["3️⃣ RECHERCHER<br/>Chercher dans dictionnaire<br/>pour $TIME_OFFSET"]
Found["4️⃣ TROUVÉ<br/>Valeur:<br/>'125'"]
Replace["5️⃣ REMPLACER<br/>num_x = <br/>'125'"]
Ready["6️⃣ PRÊT<br/>Paramètre résolu<br/>Prêt pour casting"]
Scan --> Identify
Identify --> Lookup
Lookup --> Found
Found --> Replace
Replace --> Ready
style Scan fill:#fff9c4
style Identify fill:#fff9c4
style Lookup fill:#fff9c4
style Found fill:#c8e6c9
style Replace fill:#fff9c4
style Ready fill:#c8e6c9
Avant Résolution :
Note :num_x contient une référence de variable
Après Résolution :
Note :num_x contient maintenant la valeur résolue (toujours String, le casting vient ensuite)
"text_y": "unreachable",
"compare_type": 2
}
---
## Étape 4 : Casting de Type
Après résolution, les valeurs sont **converties au type attendu du paramètre**.
### Types de Casting
| De | À | Exemple | Processus |
|-----|-----|---------|----------|
| String | String | `"Network is unreachable"` | Pas de conversion |
| String | Double | `"25.5"` | Parser en float: `25.5` |
| String | JSON | `'{"status": "ok"}'` | Parser en objet: `{status: "ok"}` |
| String | Boolean | `"true"` | Parser en booléen: `true` |
### Exemple de Casting
```json
{
"CompareNumber": [
{
"id": "3",
"num_x": "$TEMPERATURE",
"num_y": "50.0",
"compare_type": 1
}
]
}
flowchart TD
Before["AVANT CASTING<br/>num_x = TEMPERATURE<br/>(String du dictionnaire)"]
Resolved["APRES RESOLUTION<br/>num_x = 38.5<br/>(Toujours type String)"]
CheckType["VERIFIER TYPE<br/>num_x s attend a: Double<br/>Type actuel: String"]
Convert["CONVERTIR<br/>String 38.5<br/>vers Double 38.5<br/>(type cast)"]
CastSuccess["CASTING REUSSI<br/>num_x = 38.5<br/>(Type Double)<br/>Pret pour execution"]
CastError["ERREUR CASTING<br/>Impossible convertir abc<br/>en Double<br/>Execution s arrete"]
Before --> Resolved
Resolved --> CheckType
CheckType --> Convert
Convert --> CastSuccess
CheckType -->|Valeur invalide| CastError
style Before fill:#ffe0e0
style Resolved fill:#fff9c4
style CheckType fill:#fff9c4
style Convert fill:#fff9c4
style CastSuccess fill:#c8e6c9
style CastError fill:#ffcdd2
Exemple Complet d'Exécution de Workflow
JSON du Workflow
{
"Start": [
{
"id": "0",
"variables": [
{"variableName": "$PING_ERROR", "variableValue": ""},
{"variableName": "$TEMPERATURE", "variableValue": "0.0"}
]
}
],
"CmdStage": [
{
"id": "1",
"cmd_text": "ping -c 1 8.8.8.8",
"cmd_error_output": "$PING_ERROR"
}
],
"CompareText": [
{
"id": "2",
"text_x": "$PING_ERROR",
"text_y": "unreachable",
"compare_type": 2
}
],
"TextReport": [
{
"id": "3",
"texte": "Réseau inaccessible: $PING_ERROR"
},
{
"id": "4",
"texte": "Réseau OK"
}
],
"End": [{"id": "100"}],
"Links": [
{"from": "0", "to": "1"},
{"from": "1", "to": "2"},
{"from": "2", "true": "3", "false": "4"},
{"from": "3", "to": "100"},
{"from": "4", "to": "100"}
]
}
Tableau d'Exécution
| Étape | Tâche | Opération | État Dictionnaire | Notes |
|---|---|---|---|---|
| 1 | START (id:0) | Initialiser variables | {"$PING_ERROR": "", "$TEMPERATURE": "0.0"} |
Valeurs vides |
| 2 | CmdStage (id:1) | Exécuter ping | Identique | Commande lancée... |
| 3 | CmdStage (id:1) | Commande échoue | Identique | Erreur se produit |
| 4 | Runtime Resolver | Enregistrer output | {"$PING_ERROR": "Network is unreachable", "$TEMPERATURE": "0.0"} |
$PING_ERROR mise à jour |
| 5 | CompareText (id:2) | Attendre exécution | Identique | Tâche prête |
| 6 | Runtime Resolver | Résoudre paramètres | Identique | Scanne: text_x: "$PING_ERROR" |
| 7 | Runtime Resolver | Remplacer variable | Identique | text_x = "Network is unreachable" |
| 8 | Runtime Resolver | Caster types | Identique | text_x: String → String (pas changement) |
| 9 | CompareText (id:2) | Exécuter comparaison | Identique | Compare contient "unreachable" |
| 10 | CompareText (id:2) | Résultat: VRAI | Identique | Condition confirmée |
| 11 | Runtime Resolver | Brancher vers Tâche 3 | Identique | Suivre lien "true" |
| 12 | TextReport (id:3) | Attendre exécution | Identique | Tâche prête |
| 13 | Runtime Resolver | Résoudre texte | Identique | Résoudre $PING_ERROR dans texte |
| 14 | TextReport (id:3) | Exécuter avec texte résolu | Identique | Afficher message résolu |
| 15 | END (id:100) | Workflow terminé | Identique | État final atteint |
Timeline Visuelle d'Exécution
Exemple Concret : Vérifier le RTT NTP (Round Trip Time) avant d'accepter l'offset. Si RTT > 100ms, réessayer la synchronisation.
sequenceDiagram
autonumber
participant Start as 🏁 START
participant Dict as 📦 Dictionnaire
participant NTP1 as ⚙️ NtpSync 1
participant Resolver as 🔍 Resolver
participant CmpNum2 as 🔢 Compare 2
participant NTP3 as 🔄 NtpSync 3
participant CmpNum4 as 🔢 Compare 4
participant Report as 📄 Report 5
participant EndNode as 🎯 END
rect rgb(230, 240, 255)
Note over Start,Dict: 📋 PHASE 1 - INITIALISATION
Start->>Dict: Initialiser Variables
Note over Dict: Dictionnaire Créé
Note over Dict: {$NTP_RTT: 0, $TIME_OFFSET: 0}
end
rect rgb(245, 230, 255)
Note over Dict,NTP1: ⚙️ PHASE 2 - PREMIERE SYNC NTP
Dict->>NTP1: Exécuter Tâche 1
NTP1->>NTP1: Interroger time.google.com
Note over NTP1: Réponse RTT: 300ms, Offset: 125ms
NTP1->>Resolver: Output RTT=300, Offset=125
Resolver->>Dict: Enregistrer Outputs
Note over Dict: Dictionnaire Mis à Jour
Note over Dict: {$NTP_RTT: 300, $TIME_OFFSET: 125}
end
rect rgb(255, 250, 230)
Note over Dict,CmpNum2: 🔍 PHASE 3 - VERIFIER QUALITE RTT
Dict->>CmpNum2: Exécuter Tâche 2
CmpNum2->>Resolver: Résoudre param $NTP_RTT
Resolver->>Dict: Chercher $NTP_RTT
Dict-->>Resolver: Retourner 300
Resolver->>CmpNum2: num_x = 300 (cast en Integer)
CmpNum2->>CmpNum2: Comparer 300 < 100
Note over CmpNum2: Résultat FALSE - RTT trop élevé!
CmpNum2->>Dict: Brancher vers chemin FALSE
end
rect rgb(230, 255, 245)
Note over Dict,NTP3: 🔄 PHASE 4 - REESSAYER SYNC NTP
Dict->>NTP3: Exécuter Tâche 3 (Retry)
NTP3->>NTP3: Interroger pool.ntp.org
Note over NTP3: Réponse RTT: 45ms, Offset: 98ms
NTP3->>Resolver: Output RTT=45, Offset=98
Resolver->>Dict: Mettre à Jour Dictionnaire
Note over Dict: Dictionnaire Mis à Jour
Note over Dict: {$NTP_RTT: 45, $TIME_OFFSET: 98}
end
rect rgb(255, 250, 230)
Note over Dict,CmpNum4: 🔍 PHASE 5 - REVERIFIER RTT
Dict->>CmpNum4: Exécuter Tâche 4
CmpNum4->>Resolver: Résoudre param $NTP_RTT
Resolver->>Dict: Chercher $NTP_RTT
Dict-->>Resolver: Retourner 45
Resolver->>CmpNum4: num_x = 45 (cast en Integer)
CmpNum4->>CmpNum4: Comparer 45 < 100
Note over CmpNum4: Résultat TRUE - RTT acceptable!
CmpNum4->>Dict: Brancher vers chemin TRUE
end
rect rgb(240, 255, 240)
Note over Dict,Report: 📄 PHASE 6 - RAPPORT SUCCES
Dict->>Report: Exécuter Tâche 5
Report->>Resolver: Résoudre $NTP_RTT et $TIME_OFFSET
Resolver->>Dict: Chercher les deux variables
Dict-->>Resolver: $NTP_RTT=45, $TIME_OFFSET=98
Resolver->>Report: Multi-variable résolu
Report->>Report: Afficher message
Note over Report: Sync NTP OK! RTT: 45 ms, Offset: 98 ms
end
rect rgb(230, 255, 230)
Note over Report,EndNode: 🎯 PHASE 7 - COMPLETION
Report->>EndNode: Workflow Terminé
Note over Dict: État Final
Note over Dict: {$NTP_RTT: 45, $TIME_OFFSET: 98}
end
Résolution Multi-Variables
Un paramètre peut contenir plusieurs variables qui ont toutes besoin de résolution :
{
"TextReport": [
{
"id": "5",
"texte": "Offset NTP: $TIME_OFFSET ms | Localisation: Latitude $LATITUDE"
}
]
}
Étapes de Résolution
flowchart LR
Text["Paramètre texte:<br/>'Offset NTP: $TIME_OFFSET ms<br/>Localisation: Latitude $LATITUDE'"]
Find["TROUVER variables:<br/>$TIME_OFFSET<br/>$LATITUDE"]
Lookup1["CHERCHER $TIME_OFFSET:<br/>Trouvé: '125'"]
Lookup2["CHERCHER $LATITUDE:<br/>Trouvé: '48.8566'"]
Replace["REMPLACER les deux:<br/>'Offset NTP: 125 ms<br/>Localisation: Latitude 48.8566'"]
Ready["PRÊT pour exécution"]
Text --> Find
Find --> Lookup1
Find --> Lookup2
Lookup1 --> Replace
Lookup2 --> Replace
Replace --> Ready
style Text fill:#ffe0e0
style Find fill:#fff9c4
style Lookup1 fill:#fff9c4
style Lookup2 fill:#fff9c4
style Replace fill:#c8e6c9
style Ready fill:#c8e6c9
Text["Parametre texte:Erreur: PING_ERROR
Temp: TEMPERATURE"]
Find["TROUVER variables:<br/>PING_ERROR<br/>TEMPERATURE"]
Lookup1["RECHERCHER PING_ERROR:<br/>Trouve: Network unreachable"]
Lookup2["RECHERCHER TEMPERATURE:<br/>Trouve: 38.5"]
Replace["REMPLACER les deux:<br/>Erreur: Network unreachable<br/>Temp: 38.5"]
Ready["PRET pour execution"]
Text --> Find
Find --> Lookup1
Find --> Lookup2
Lookup1 --> Replace
Lookup2 --> Replace
Replace --> Ready
style Text fill:#ffe0e0
style Find fill:#fff9c4
style Lookup1 fill:#fff9c4
style Lookup2 fill:#fff9c4
style Replace fill:#c8e6c9
style Ready fill:#c8e6c9
```
Scénarios d'Erreur
Scénario 1 : Variable Non Déclarée
json
{
"CompareText": [
{
"id": "2",
"text_x": "$UNDEFINED_VAR",
"text_y": "test"
}
]
}
flowchart TD
Scan["SCANNER parametre<br/>Trouver: UNDEFINED_VAR"]
Lookup["RECHERCHER en dictionnaire<br/>Chercher: UNDEFINED_VAR"]
NotFound["NON TROUVEE<br/>Variable n existe pas"]
Error["ERREUR<br/>Variable UNDEFINED_VAR<br/>non trouvee en<br/>dictionnaire runtime"]
Stop["ARRETER EXECUTION<br/>Workflow echoue"]
Scan --> Lookup
Lookup --> NotFound
NotFound --> Error
Error --> Stop
style Scan fill:#fff9c4
style Lookup fill:#fff9c4
style NotFound fill:#ffcdd2
style Error fill:#ffcdd2
style Stop fill:#ffcdd2
Scénario 2 : Erreur de Casting
Dictionnaire: {"$TEXT_VALUE": "abc"} (pas un nombre valide)
flowchart TD
Resolve["RESOUDRE<br/>num_x = abc"]
CheckType["VERIFIER TYPE<br/>num_x s attend: Double<br/>Actuel: String"]
TryConvert["ESSAYER CONVERTIR<br/>abc vers Double"]
ConvertFail["CONVERSION ECHOUE<br/>abc n est pas<br/>un nombre valide"]
Error["ERREUR<br/>Impossible caster abc<br/>en Double"]
Stop["ARRETER EXECUTION"]
Resolve --> CheckType
CheckType --> TryConvert
TryConvert --> ConvertFail
ConvertFail --> Error
Error --> Stop
style Resolve fill:#ffe0e0
style CheckType fill:#fff9c4
style TryConvert fill:#fff9c4
style ConvertFail fill:#ffcdd2
style Error fill:#ffcdd2
style Stop fill:#ffcdd2
Machine d'État du Dictionnaire Runtime
Le dictionnaire runtime évolue au cours du cycle de vie du workflow :
flowchart TD
Start["START NODE<br/>Dictionary Initialization<br/>Variables declared<br/>Initial values set"]
Task1Ready["Task 1 Ready<br/>Waiting for execution"]
Task1Exec["Task 1 Execution<br/>Processing command<br/>Generating output"]
Task1Register["Register Output<br/>Runtime Resolver saves<br/>Output to Dictionary<br/>VAR1 = value1"]
Task1Done["Task 1 Complete<br/>Dictionary Updated<br/>New state stored"]
Task2Ready["Task 2 Ready<br/>Waiting for execution<br/>Has parameters"]
Task2Scan["Scan Parameters<br/>Runtime Resolver finds<br/>Variable references"]
Task2Resolve["Resolve Variables<br/>Replace variables<br/>With dictionary values"]
Task2Cast["Cast Types<br/>Convert to expected<br/>Parameter types"]
Task2Exec["Task 2 Execution<br/>Using resolved values<br/>Parameters ready"]
Task2Done["Task 2 Complete<br/>Output registered<br/>Dictionary extends"]
End["WORKFLOW END<br/>Final dictionary state<br/>All variables persisted"]
Start --> Task1Ready
Task1Ready --> Task1Exec
Task1Exec --> Task1Register
Task1Register --> Task1Done
Task1Done --> Task2Ready
Task2Ready --> Task2Scan
Task2Scan --> Task2Resolve
Task2Resolve --> Task2Cast
Task2Cast --> Task2Exec
Task2Exec --> Task2Done
Task2Done --> End
style Start fill:#c8e6c9
style Task1Ready fill:#e3f2fd
style Task1Exec fill:#f3e5f5
style Task1Register fill:#fff9c4
style Task1Done fill:#c8e6c9
style Task2Ready fill:#e3f2fd
style Task2Scan fill:#fff9c4
style Task2Resolve fill:#fff9c4
style Task2Cast fill:#fff9c4
style Task2Exec fill:#f3e5f5
style Task2Done fill:#c8e6c9
style End fill:#c8e6c9
Bonnes Pratiques pour la Résolution Runtime
1. Déclarer les Variables Tôt
Toujours déclarer toutes les variables au nœud START :
✅ Bon : Toutes variables déclarées au départ
{
"Start": [{"id": "0", "variables": [...]}]
}
❌ Mauvais : Déclarations manquantes
{
"CmdStage": [{"id": "1", "cmd_error_output": "$UNDEFINED"}]
}
2. Utiliser des Noms de Variables Descriptifs
✅ Bon : But clair
"cmd_error_output": "$PING_ERROR"
"cmd_result_output": "$NETWORK_STATUS"
❌ Mauvais : Noms génériques
"cmd_error_output": "$x"
"cmd_result_output": "$var1"
3. Initialiser avec les Types Corrects
✅ Bon : Valeurs par défaut appropriées au type
{"variableName": "$ERROR_MSG", "variableValue": ""}
{"variableName": "$TEMPERATURE", "variableValue": "0.0"}
{"variableName": "$DATA", "variableValue": "{}"}
❌ Mauvais : Types mal appariés
{"variableName": "$TEMPERATURE", "variableValue": "zéro"}
4. Vérifier la Compatibilité des Types
Assurer que les types de paramètres correspondent aux castages attendus :