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.
4 Réponses :
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; }
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 ++; }
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.
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; } }