Bonjour,

Je suis entrain de monté une petite app nodeJS qui va me permetre d'exécuter un ping sur une machine depuis une instance google cloud et de m'informé si le serveur / site est hors-ligne

J'ai remplis un tableau avec mes différent serveurs

var servers = 
    {
    "server1": {
        "ip": "127.0.0.1",
        "realName": "unsite.fr"
    },
    "server2": {
        "ip": "127.0.0.2",
        "realName": "unsousdomaine.unsite.fr"
    },
    "server3": {
        "ip": "127.0.0.3",
        "realName": "uautresousdomaine.unautresite.fr"
    }
}

Jusque ici aucun soucis j'ai testé de récupéré mon tableau pour test ok tout est ok

for (var server in servers) {
    console.log("srv ip:" + servers[server]["ip"]);
    console.log("srv name:" + servers[server]["realName"]);
 }

root@imchip:/home/app/node-monitoring# node monitoring.js
srv ip:127.0.0.1
srv name:unsite.fr
srv ip:127.0.0.2
srv name:unsousdomaine.unsite.fr
srv ip:127.0.0.3
srv name:uautresousdomaine.unautresite.fr

Maintenant j'utilise une librarie npm qui se nome "net-ping"

Pour récup mes donnée j'ai utiliser deux var
Une var IP et une var Name
Hors ceux ci me retourne toujours le dernier serveur hors que il ne devrais pas

root@imchip:/home/app/node-monitoring# node monitoring.js
uautresousdomaine.unautresite.fr is UP
uautresousdomaine.unautresite.fr is UP
uautresousdomaine.unautresite.fr is UP

Code complet:

var ping = require ("net-ping");
var servers = 
    {
    "server1": {
        "ip": "127.0.0.1",
        "realName": "unsite.fr"
    },
    "server2": {
        "ip": "127.0.0.2",
        "realName": "unsousdomaine.unsite.fr"
    },
    "server3": {
        "ip": "127.0.0.3",
        "realName": "uautresousdomaine.unautresite.fr"
    }
}

for (var server in servers) { 
   var session = ping.createSession ();
   var ip = servers[server]["ip"];
   var name = servers[server]["realName"];

// Check 
session.pingHost (ip, function (error, target) {
   if (error)
       if (error instanceof ping.RequestTimedOutError) {
           console.log (name + " is DOWN");
      } else {
           console.log (name + " ERROR" + error.toString ());
    } else {
      console.log (name + " is UP");       
    }
});
}

Désolé pour les faute et merci d'avance
Ainsi que une bonne année a vous tous :)

3 réponses


Renan Decamps
Réponse acceptée

Salut Chipie678,

Ton problème ne vient pas de ta boucle foreach, mais de ton appel à la fonction pingHost().
Je ne me suis pas renseigné, mais je pense que cette fonction est une fonction asynchrone (plus de détail ici si tu ne vois pas de quoi je parle ;) ).
Ton vrai problème c'est que tu lances un appel à cette fonction en utilisant les variables ip et name dans celle-ci en tout en les ayant déclarées à l'exterieur : à chaque tour de boucle, tes variables sont réaffectées et leur valeur change tandis que ta fonction n'a toujours pas fini de s'exécuter.
Une solution serait de passer une copie de ces variables en utilisant des closures.
Un exemple valant toujours mieux qu'un long discours :

for (var server in servers) { 
  var session = ping.createSession ();
  var ip = servers[server]["ip"];
  var name = servers[server]["realName"];

  // Check 
  (function(ip_copie, name_copie) {
    session.pingHost (ip, function (error, target) {
      if (error) {
        if (error instanceof ping.RequestTimedOutError) {
            console.log (name + " is DOWN");
        } else {
            console.log (name + " ERROR" + error.toString ());
        } else {
            console.log (name + " is UP");       
        }
      }
    });
  })(ip, name); // Les variables sont passées en paramètres de la fonction closure.

}

Je n'ai pas testé ce code, mais je pense que la solution est de ce côté ;)

J'espère avoir répondu à ta question ^^

En effet comme Renan l'a dit, c'est que la méthode pingHost utilise 3 fois une variable dans le contexte globale, ainsi c'est la dernière affectation qui est utilisée. On peut même faire une trace.

    1. Premier tour de boucle
    1. Valeur de ip = 127.0.0.1
    1. Valeur de name = unsite.fr
    1. Inscription de la méthode anonyme dans session.pingHost
    1. Deuxième tour de boucle
    1. Valeur de ip = 127.0.0.2
    1. Valeur de name = unsousdomaine.unsite.fr
    1. Inscription de la méthode anonyme dans session.pingHost
    1. Troisième tour de boucle
    1. Valeur de ip = 127.0.0.3
    1. Valeur de name = uautresousdomaine.unautresite.fr
    1. Inscription de la méthode anonyme dans session.pingHost
    1. Exécution de la méthode anonyme inscrite au point 4.
    1. La valeur de ip est de 127.0.0.3 et name est de uautresousdomaine.unautresite.fr
    1. Exécution de la méthode anonyme inscrite au point 8.
    1. La valeur de ip est de 127.0.0.3 et name est de uautresousdomaine.unautresite.fr
    1. Exécution de la méthode anonyme inscrite au point 12.
    1. La valeur de ip est de 127.0.0.3 et name est de uautresousdomaine.unautresite.fr

L'exécution des étapes 13 à 18 peuvent changer d'ordre, la dernière pourrait même s'exécuter avant la première, puisque c'est une opération asynchrone ! La solution de Reven est valide ! Il y aurait peut-être d'autres méthodes afin que le résultat arrive dans le bon ordre, comme attendre la réponse du premier résultat avant de lancer le prochain... on pourrait imager d'autres choses j'imagine ! :-)

Merci beaucou pour vos réponse
J'ai réussis avec l'exemple de Renan
Je copierais mon code ici demain :)