2
votes

nodejs retry function en cas d'échec X fois

Je veux que ma fonction exécute X (= 3) fois jusqu'à ce qu'elle réussisse.

Dans ma situation, j'exécute kinesis.putRecord (depuis l'API AWS), et si elle échoue, je Je veux le relancer jusqu'à ce qu'il réussisse, mais pas plus de 3 essais.

Je suis nouveau sur NodeJS, et le code que j'ai écrit sent mauvais.

const putRecordsPromise = function(params){
    return new Promise((resolve, reject) => {
        kinesis.putRecord(params, function (err, data) {
            resolve(err)
        });
    })
}

async function waterfall(params){
    try{
        let triesCounter = 0;
        while(triesCounter < 2){
            console.log(`try #${triesCounter}`)
            let recordsAnswer = await putRecordsPromise(params)
            if(!recordsAnswer){
                console.log("success")
                break;
            }
            triesCounter += 1;
        }
        // continue ...

    } catch(err){
        console.error(err)
    }
}

waterfall(params)

Je promets le résultat d'erreur. Ensuite, si l'erreur est vide, tout va bien. sinon, continuez à exécuter la même commande.

Je suis sûr qu'il existe un moyen plus intelligent de faire cela. Toute aide serait appréciée.


0 commentaires

4 Réponses :


1
votes

Créez un petit module, dites try-and-try-again.js:

const tryAndTryAgain = require('./try-and-try-again');

function somethingThatMightNeedARetry() { ... }

const succeeded = tryAndTryAgain( 3 , null, somethingThatMightNeedARetry, 'arg-1', 'arg-2', 'arg-3' );

Ensuite, vous pouvez l'utiliser n'importe où:

exports = module.exports = tryAndTryAgain;

function tryUntilSuccess( maxTries, thisContext , fn, ...argv) {
  let success = false;

  for (let i = i ; i < maxTries && !success ; ++i ) {
    let rc = fn.apply(thisContext, args);
    success = rc == 0 ? true : false;
  }

  return success;
}


0 commentaires

6
votes

Je pense que toutes les fonctions Aws peuvent renvoyer une promesse prête à l'emploi, alors vous pouvez simplement mettre l'appel dans try/catch:

let triesCounter = 0;
while(triesCounter < 2){
    console.log(`try #${triesCounter}`)
    try {
        await kinesis.putRecord(params).promise();
        break;  // 'return' would work here as well
    } catch (err) {
       console.log(err);
    }
    triesCounter ++;
}


7 commentaires

il lance SyntaxError: await n'est valide que dans la fonction asynchrone


@TheCrystalShip, dans votre question, vous aviez le code dans une fonction async , donc on suppose que vous mettez ce code de réponse dans la fonction async .


Pit mon extrait dans votre fonction cascade . Il est déjà asynchrone


Une autre amélioration serait d'utiliser une boucle for classique, au lieu de while .


@trincot dans la mesure où nous voulons exécuter du code uniquement jusqu'à ce qu'il réussisse, je trouve while ici mieux, car pour avec break pourrait être déroutant. ..


L'avantage de for (let ... est que la variable de boucle a une portée de bloc uniquement dans la boucle. Je ne sais pas pourquoi break serait plus déroutant dans un pour . C'est à cela que sert break .


@trincot Je pense que c'est juste une question de goût, votre argument est valable.



4
votes

Dans un style fonctionnel:

...
await tryUntilSucceed(() => kinesis.putRecord(params).promise());
...

async function tryUntilSucceed(promiseFn, maxTries=3) {
    try {
        return await promiseFn();
    } catch (e) {
        if (maxTries > 0) {
            return tryUntilSucceed(promiseFn, maxTries - 1);
        }
        throw e;
    }
}


0 commentaires