Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Promise Retry Design Patterns

Edit

  1. Pattern that keep on retrying until the promise resolves (with delay and maxRetries).
  2. Pattern that keeps on retrying until the condition meets on the result (with delay and maxRetries).
  3. A memory efficient dynamic Pattern with unlimited retries (delay provided).

Code for #1. Keeps on retrying until promise resolves (any improvements community for the language etc?)

Promise.retry = function(fn, times, delay) {     return new Promise(function(resolve, reject){         var error;         var attempt = function() {             if (times == 0) {                 reject(error);             } else {                 fn().then(resolve)                     .catch(function(e){                         times--;                         error = e;                         setTimeout(function(){attempt()}, delay);                     });             }         };         attempt();     }); }; 

Use

work.getStatus()     .then(function(result){ //retry, some glitch in the system         return Promise.retry(work.unpublish.bind(work, result), 10, 2000);     })     .then(function(){console.log('done')})     .catch(console.error); 

Code for #2 keep on retrying until a condition meets on the then result in a reusable way (condition is what will vary).

work.publish()     .then(function(result){         return new Promise(function(resolve, reject){             var intervalId = setInterval(function(){                 work.requestStatus(result).then(function(result2){                     switch(result2.status) {                         case "progress": break; //do nothing                         case "success": clearInterval(intervalId); resolve(result2); break;                         case "failure": clearInterval(intervalId); reject(result2); break;                     }                 }).catch(function(error){clearInterval(intervalId); reject(error)});             }, 1000);         });     })     .then(function(){console.log('done')})     .catch(console.error); 
like image 994
user2727195 Avatar asked Jul 05 '16 22:07

user2727195


People also ask

How do you retry a rejected promise?

To retry the promise we have to call the same function recursively with reduced max tries, if the promise failed that is in the catch block. Check if there is a number of tries left then recursively call the same function or else reject with the final error.

What happens if a promise doesn't resolve?

A promise is just an object with properties in Javascript. There's no magic to it. So failing to resolve or reject a promise just fails to ever change the state from "pending" to anything else. This doesn't cause any fundamental problem in Javascript because a promise is just a regular Javascript object.

Does Promise Return After resolve?

The Promise. resolve() method "resolves" a given value to a Promise . If the value is a promise, that promise is returned; if the value is a thenable, Promise. resolve() will call the then() method with two callbacks it prepared; otherwise the returned promise will be fulfilled with the value.

How do you implement retry logic in node JS?

import fetch from 'node-fetch'; let attempts = 0; const wait = (time = 0) => { return new Promise((resolve) => { setTimeout(() => { resolve(); }, time * 1000); }); }; const retryFetch = async (url = '', options = {}) => { const { retry = null, retryDelay = 0, retries = 5, ...


1 Answers

Something a bit different ...

Async retries can be achieved by building a .catch() chain, as opposed to the more usual .then() chain.

This approach is :

  • only possible with a specified maximum number of attempts. (The chain must be of finite length),
  • only advisable with a low maximum. (Promise chains consume memory roughly proportional to their length).

Otherwise, use a recursive solution.

First, a utility function to be used as a .catch() callback.

var t = 500;  function rejectDelay(reason) {     return new Promise(function(resolve, reject) {         setTimeout(reject.bind(null, reason), t);      }); } 

Now you can build .catch chains very concisely :

1. Retry until the promise resolves, with delay

var max = 5; var p = Promise.reject();  for(var i=0; i<max; i++) {     p = p.catch(attempt).catch(rejectDelay); } p = p.then(processResult).catch(errorHandler); 

DEMO: https://jsfiddle.net/duL0qjqe/

2. Retry until result meets some condition, without delay

var max = 5; var p = Promise.reject();  for(var i=0; i<max; i++) {     p = p.catch(attempt).then(test); } p = p.then(processResult).catch(errorHandler); 

DEMO: https://jsfiddle.net/duL0qjqe/1/

3. Retry until result meets some condition, with delay

Having got your mind round (1) and (2), a combined test+delay is equally trivial.

var max = 5; var p = Promise.reject();  for(var i=0; i<max; i++) {     p = p.catch(attempt).then(test).catch(rejectDelay);     // Don't be tempted to simplify this to `p.catch(attempt).then(test, rejectDelay)`. Test failures would not be caught. } p = p.then(processResult).catch(errorHandler); 

test() can be synchronous or asynchronous.

It would also be trivial to add further tests. Simply sandwich a chain of thens between the two catches.

p = p.catch(attempt).then(test1).then(test2).then(test3).catch(rejectDelay); 

DEMO: https://jsfiddle.net/duL0qjqe/3/


All versions are designed for attempt to be a promise-returning async function. It could also conceivably return a value, in which case the chain would follow its success path to the next/terminal .then().

like image 135
Roamer-1888 Avatar answered Sep 17 '22 21:09

Roamer-1888