Edge
Edge

Reputation: 2540

Recursive promise for failed requests

I have a main function that makes a series of GET requests in parallel. Their status is evaluated using the Promise.all function.

var promises = [];

for ( var i = 0; i < list.length; i++ )
{
   promises.push( REQ( list[ i ], 0 ) );
}

var responses = await Promise.all( promises );

The REQ function returns a promise.

async function REQ( url, attempts )
{
   await sleep( 5000 * attempts ); // Uses a promise with setTimeout

   return new Promise( ( resolve, reject ) => {
      request( url, function ( error, response, body )
      {
         if ( error )
         {
            if ( attempts > ATTEMPT_THRESHOLD )
               reject( error );
            else
               return REQ( url, ++attempts );
         }
         else
         {
            if ( typeof body === 'undefined' || body.length === 0 )
            {
               if ( attempts > ATTEMPT_THRESHOLD )
                  reject( error );
               else
                  return REQ( url, ++attempts );
            }
            else
               resolve( { response, body } );
         }
      });
   });
};

The reason I've made the REQ function async is so that if a request fails, it gets re-attempted, but the re-attempt is delayed a little in case the server it's querying is congested.

The issue seems to be that in the Node console, the program hangs on a re-attempt, such that if a REQ fails, the re-attempt of it doesn't return to the original REQ and return the promise.

Upvotes: 1

Views: 122

Answers (1)

Bergi
Bergi

Reputation: 664493

The re-attempt of it doesn't return to the original REQ and return the promise.

Of course not. In a new Promise constructor, you need to resolve the promise not return it.

It would be much better if you promisified on the lowest possible level, i.e. just wrap request and only request, not any of the retry business logic:

function requestAsync(url) {
  return new Promise((resolve, reject) => {
    request(url, (error, response, body) => {
      if (error) reject(error);
      else resolve({response, body});
    });
  });
}

Then you can use await and return as usual.

async function REQ(url, attempts) {
  try {
    const res = await requestAsync(url);
    if (typeof res.body == "undefined" || res.body.length == 0)
      throw new Error("no response"); // or throw undefined to get the original behaviour
    return res;
  } catch(error) {
    if (attempts > ATTEMPT_THRESHOLD)
      throw error;
    ++attempts;
    await sleep(5000 * attempts);
    return REQ(url, attempts);
  }
}

Upvotes: 2

Related Questions