Bonjour tout le monde ,

J'ai une petite applet nodeJS qui tourne sur raspberry pi 0 avec un setInterval qui me sert a mesurer la température.
Or, ce setInterval() s'arrête systématiquement tout seul a bout d'un certain nombre d'utilisation.

ci joint, le lien vers un autre forum ou j'ai aussi posé mon problème : https://openclassrooms.com/forum/sujet/nodejs-arret-setinterval

le code :

const sondeTemperature = require('ds18b20-raspi'); // Pour utiliser une sonde ds18b20 étanche
const nodemailer = require('nodemailer'); // je me sert des mails pour recevoir les erreurs et les températures
const logs = require('fs'); // pour écrire un fichier de log
const bdd = require('mysql'); //bdd

//variables nécéssaires

const listeSonde = sondeTemperature.list(); // recense la liste des capteurs de température disponible (1 dans mon cas)
var boolTemperature = 0; // Me sert plus tard pour connaitre l'état de la sonde
const TempscooldownMail = 5; //sert pour empêcher le spam de mail, 1 mil toute les 5 minutes
var cooldownMail = 0; // un itérateur que je vais faire courrir pour les mails
var nbBoucle = 12; // nombre de cycle avant d'appeler MesurePeriodiqueHeure()

//en cas d'erreurs, les infos mails
const transporter = nodemailer.createTransport(
{
    service: 'gmail',
    auth:
    {
        user: '',
        pass: ''
    }
});

//tableau pour stocker des données const et var
var tabDonnee = new Array();

setTimeout( ()=> { // j'attend 1 seconde avant de recennser les sondes, histoire de laisser le temps a listeSonde d'être initialisé
if(listeSonde.length < 1) // si pas de sonde
{
    boolTemperature = 1; // erreur sonde a 1
    mailAlerte("sondeManquante"); // evoie d'une alerte mail
    erreurLogs("sondeManquante"); // ecriture dans les logs
    return;
}
else // si au moins une sonde
{
    tabDonnee[1] = new Array();
    tabDonnee[1][0] = listeSonde[0]; //Adresse de la sonde de température
    tabDonnee[1][1] = sondeTemperature.readC(listeSonde[0]); //température actuel en celsius
    tabDonnee[1][3] = "28.00" // température seuil haut (maximum ,dans l'aquarium)
    tabDonnee[1][4] = "25.00" // température seuil bas (minimum ,dans l'aquarium)
}
},1000);

erreurLogs("applet démarré, variables initialisés."); // petit test

let timerMinute = setInterval(() => {VerifMinute();}, 300000); //Ceci permet de boucler toute les 5 minutes sur ma fonction qui mesure la température. -- 60000

function VerifMinute() // fonction principale du programme
{
    erreurLogs("verifminute lancé"); // petit test #2
    var heure = new Date(); // variable a créer a chaque itération pour quelle sois a jour
    var temp = (heure.getHours()<10?'0':'') + heure.getHours()+":"+(heure.getMinutes()<10?'0':'') + heure.getMinutes(); // si le chiffre des heures est inférieur a 10 (donc de 0 à 9) il faut ajouter un 0 non significatif devant

    //vérification de la température et des seuils
    if(boolTemperature == 0 & cooldownMail == 0) // si caoteur de température est oK et pas de mails dans les 5 dernières minutes
    {

        tabDonnee[1][1] = sondeTemperature.readC(tabDonnee[1][0]); // je lis la température
        if((tabDonnee[1][1] < tabDonnee[1][4]) | (tabDonnee[1][1] > tabDonnee[1][3])) // je compare ma lecture aux seuils a ne pas franchir
        {
            mailAlerte("seuilTemperature"); // si un seuil est franchis, j'alerte par mail
        }
    }
    if(cooldownMail > 0) cooldownMail = cooldownMail -1; // si il y a eu un mail dans les 5 dernières minutes, je décrémente mon itérateur
    if(nbBoucle > 11) // mon fameux cycle pour appeler ma deuxième fonction
    {
        nbBoucle = 0; // reset du cycle
        MesurePeriodiqueHeure(); //permet de stocker la température actuel dans une BDD
    }
    else nbBoucle = nbBoucle +1; // je note mon nouveau cycle

    heure = temp = null; // j'ai essayé de libérer les variables pour contenir la mémoire
}
function MesurePeriodiqueHeure()
{
    var dateHeure = new Date(); // sert pour récupérer l'heure
    var date = dateHeure.getFullYear()+"-"+(dateHeure.getMonth()+1)+"-"+dateHeure.getDate();
    var heure = (dateHeure.getHours()<10?'0':'') + dateHeure.getHours()+":"+(dateHeure.getMinutes()<10?'0':'') + dateHeure.getMinutes()+":"+(dateHeure.getSeconds()<10?'0':'') + dateHeure.getSeconds();
    if(boolTemperature == 0) // si mon capteur de température est ok
    {
        var mySqlClient = bdd.createConnection( // je me connecte a la BDD
        {
            host     : "localhost",
            user     : "aquarium",
            password : "",
            database : "Aquarium"
        });
        var selectQuery = "INSERT INTO `historique_temperature`(`date`, `heure`, `num_sonde`, `temperature`) VALUES (\""+date+"\",\""+heure+"\",\""+tabDonnee[1][0]+"\",\""+tabDonnee[1][1]+"\")";
        mySqlClient.query(selectQuery,function select(error, results, fields)
        {
            if (error)  //si erreur avec la requete
            {
                mySqlClient.end();// je coupe la connexion
                mailAlerte("erreurBDD"); //je mail
                erreurLogs("erreur BDD : "+error); //je log
                return;
            }
            date = heure = dateheure = null; //vidage de la mémoire
        });

    }
}

function mailAlerte(erreur) // pour alerter, pas d'explications car fonctionnel
{
    if(cooldownMail <= 0)
    {
        switch(erreur)
        {
            case "sondeManquante" :
                var mailOptions = {
                    from: '',
                    to: '',
                    cc: '',
                    subject: 'Aquarium - Attention requise',
                    text: 'Le système de l\'aquarium a détecté un problème.\n Aucune sonde de température détectée. La température ne peut pas être mesurée.\nLe problème ne peut être résolue par le système.\n L\'attention d\'un opérateur est requise. \n\n Bien à vous, Jean-Michel, BOT assistant.\n\n\n -- Robot, ne pas répondre à ce mail --'
                };
                break;
            case "seuilTemperature" :
                var mailOptions = {
                    from: '',
                    to: '',
                    cc: '',
                    subject: 'Aquarium - Attention requise',
                    text: 'Le système de l\'aquarium a détecté un problème.\n Un seuil de température a été franchi.\nTempérature actuelle : '+tabDonnee[1][1]+'°C, mesurée par la sonde : '+tabDonnee[1][0]+'\n seuil minimum : '+tabDonnee[1][4]+'°C\n seuil maximum : '+tabDonnee[1][3]+'°C\nSonde en cours de redémarrage. \n\n Bien à vous, Jean-Michel, BOT assistant.\n\n\n -- Robot, ne pas répondre à ce mail --'
                };
                break;
            case "erreurBDD" :
                var mailOptions = {
                    from: '',
                    to: '',
                    cc: '',
                    subject: 'Aquarium - Attention requise',
                    text: 'Le système de l\'aquarium a détecté un problème.\n La base de donnée a envoyé une erreur. Insertion des données impossibles. \n\n Bien à vous, Jean-Michel, BOT assistant.\n\n\n -- Robot, ne pas répondre à ce mail --'
                };
                break;
        }

        setTimeout(function()
        {
            transporter.sendMail(mailOptions, function(error, info){
            if (error) {erreurLogs("erreur mail : "+error);return;}
            else {
                cooldownMail = TempscooldownMail;
            }
            });
        },1000);
    }
}

function erreurLogs(donnee) // logs
{
    var { rss, heapTotal, heapUsed } = process.memoryUsage();
    var contenu = donnee + ".\nTaille applet : "+ rss+"\nTaille objet total : "+heapTotal+"\nTaille objet réel : "+heapUsed+"\n";
    var dateHeure = new Date();
    var heure = (dateHeure.getHours()<10?'0':'') + dateHeure.getHours()+":"+(dateHeure.getMinutes()<10?'0':'') + dateHeure.getMinutes()+":"+(dateHeure.getSeconds()<10?'0':'') + dateHeure.getSeconds();
    contenu = ""+heure+" : "+contenu+"\n";
    setTimeout (() => {
        logs.appendFile('./logs/logs.log', contenu, function (err) {
        if (err) console.log('erreur avec les logs ! + '+err);
        else {console.log("log ecrit");}
        });
        rss = heapUsed = heapTotal = contenu = dateHeure = heure = null;
    },200);
}

les logs avec les infos mémoires : https://www.cjoint.com/c/KEut3bnBca3

Quelqu'un aurait-il une idée ??

Cordialement.

6 réponses


Ha, je n'ai pas vraiment compris ce qui se passe avec les balises codes.

Salut,

Du coups ça va être difficile de te relire, tu peux éditer ton message afin de remettre en forme pour qu'on puisse t'aider ?

bonjour,
voila, j'ai compris ou étais le problème 😂. je te préviens le code n'est pas super super, mais je cherche avant tout à faire quelque chose de fonctionnel.

Bon, après quelques tests, la mémoire ne semble pas en cause, car mon log de cette contient quasiement les mêmes valeurs.
Par ailleurs, le cycle d'arrêt semble intervenir a l'itération 480 (sois environ 8 heures après le lacement de l'applet).

Pas trop d'idée.. à part peut-être regardé du côté de l'OS, c'est possible qu'il shoot le process en le prenant pour un processus "zombie". ça ferait penser à un truc dans le genre. l'applet en elle même ne génère pas X process ?

Ba de toute facon, en retestant cette journée, l'applet a cramé au bout de six heures donc aucune idée.
C'est déjà arrivé a quelqu'un que l'applet sois kill comme ca ?
Et pourquoi l'OS tuerais mon applet ? ha ba oui, c'est logique... Pas d'intéraction donc process fantôme.
Vous pensez que cela arriverais sur un programme C ? Au pire, je peut le réécrire mais le connecteur MariaDB c'est l'enfer (d'ou mon choix du node).