0

I'm studying the node.js module async,I want to find out if there is a way to change the async.retry method to retry even on successfull operations but stop based on some condition or response let's say its an api call.

According to its docs ,the function will continue trying the task on failures until it succeeds.if it succeeds it will only run only that time But how can i make it work the same on successfull operations and make it stop on some condition ?

const async = require('async');
const axios = require('axios');

const api = async () => {
    const uri = 'https://jsonplaceholder.typicode.com/todos/1';

    try {
        const results = await axios.get(uri);
        return results.data;
    } catch (error) {
        throw error;
    }
};

const retryPolicy = async (apiMethod) => {
    async.retry({ times: 3, interval: 200 }, apiMethod, function (err, result) {
        // should retry untill the condition is met
        if (result.data.userId == 5) {
            // stop retring
        }
    });
};

retryPolicy(api);
David Tembo
  • 79
  • 3
  • 10

2 Answers2

0

I don't think this is possible. On the async.retry documentation you can find this description:

Attempts to get a successful response from task no more than times times before returning an error. If the task is successful, the callback will be passed the result of the successful task. If all attempts fail, the callback will be passed the error and result (if any) of the final attempt.

However, using the delay function given here, you can do what you want another way:

const async = require('async');
const axios = require('axios');

const delay = (t, val) => {
   return new Promise((resolve) => {
       setTimeout(() => { resolve(val) }, t);
   });
}

const api = async () => {
    const uri = 'https://jsonplaceholder.typicode.com/todos/1';

    try {
        const results = await axios.get(uri);
        return results.data;
    } catch (error) {
        throw error;
    }
};

const retryPolicy = async (apiMethod) => {
    const times = 3
    const interval = 200
    let data

    for (count = 0; count < 3; count++) {
        try {
            data = await apiMethod()
        catch(e) {
            console.log(e)
            await delay(interval)
            continue
        }
        if (data.userId === 5) {
            break;
        }

        await delay(interval)
    }
   
    // do something
};

retryPolicy(api);
Kharente Deuh
  • 206
  • 2
  • 6
  • Thanks. is this scalable lets say in an environement where you receive over 1000 requests and for each request i run this code snippet for like 1 minute per request? – David Tembo Jun 17 '21 at 08:29
  • but there is an easier way... just fail the request with throwing the error if the data doesn't fit your needs, it the request itself, check my answer – Flash Thunder Jun 17 '21 at 08:31
  • I indeed think Flash's answer is much simplier than mine and that does exactly what you want. – Kharente Deuh Jun 17 '21 at 09:16
  • I don't relly know, but i think running this code for 1min per request might be somehow heavy. But i don't see another way to do what you want a more lightly way – Kharente Deuh Jun 17 '21 at 09:25
0

Yes, You can just throw a custom error if condition is not met. Would be something like that:

const async = require('async');
const axios = require('axios');

const api = async () => {
    const uri = 'https://jsonplaceholder.typicode.com/todos/1';

    try {
        const results = await axios.get(uri);
        if(typeof result.data.userId != 'undefined' && result.data.userId == 5){ // change this condition to fit your needs
            return results.data;
        }else{
            throw {name : "BadDataError", message : "I don't like the data I got"}; 
        }
    } catch (error) {
        throw error;
    }
};
Flash Thunder
  • 11,672
  • 8
  • 47
  • 91