Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

124
Views
Racing web request promises recursively

I have a web request that sometimes completes in .1 seconds, and sometimes completes in 20 seconds. My solution is to send requests with a timeout. When the timeout triggers, I want to send another request. However, I want to leave the previous request open, and race it against the new request. I want to do this until one of the open requests completes, ending the race for all open requests.
I'm also open to suggestions for an alternative approach to this problem.

const timeoutLimit = 300;
const timeoutMessage = 'Response timed out';

/** Executes a request, retrying on timeouts, until it returns successfully. */
export default async function requestWithTimeout(request, count) {
  const timeout = new Promise((resolve, reject) => {
    setTimeout(() => reject(timeoutMessage), timeoutLimit);
  });

  const apiCall = new Promise((resolve, reject) => {
    request
      .catch((err) => reject(err))
      .then((resp) => resolve(resp));
  });

  count += 1;

  const result = await Promise.race([apiCall, timeout])
    .catch((err) => {
      console.log(err, count);
      return (err === timeoutMessage) ? Promise.race([apiCall, requestWithTimeout(request, count)]) : err;
    })
    .then((val) => {
      console.log('returned', count);
      return val;
    });

  console.log(count, result);

  return result;
}

Here is an example of the output from the console: print statements indicating timeout and response order

I always get things printed in this order:

Response timed out 1
Response timed out 2
returned 1
returned 2
returned 3
data 1
data 2
data 3

But I want my response to be something like this:

Response timed out 1
Response timed out 2
returned 1
data 1
returned 3
data 3
returned 2
data 2
about 4 years ago · Juan Pablo Isaza
1 answers
Answer question

0

My solution was to use an array to keep track of pending promises. In this way, I can open a request, and race it against the previous, still pending requests that lost a race against a timeout promise. The races will end whenever one of the pending request promises is fulfilled. This will slowly build an array of requests every timeout period, until one of them is fulfilled. By slowly increasing the number of concurrent requests instead of discarding them after the timeout period, I want to increase the likelihood that one of the requests is fulfilled by my server with an erratic response time.

const timeoutLimit = 250;
const timeoutLimitMessage = 'Response timed out, retrying';
const requestLimit = 20;
const RequestLimitMessage = 'Too many requests';

/** Executes a request, retrying on timeouts, until it returns successfully. */
export default async function requestWithTimeout(request, promises = []) {
  const timeout = new Promise((resolve, reject) => {
    setTimeout(() => reject(timeoutLimitMessage), timeoutLimit);
  });

  const apiCall = new Promise((resolve, reject) => {
    request
      .catch((err) => reject(err))
      .then((resp) => resolve(resp));
  });

  promises.push(apiCall);

  const result = await Promise.race([...promises, timeout])
    .catch((err) => {
      if (err !== timeoutLimitMessage) {
        return err;
      }
      console.log(timeoutLimitMessage);
      if (promises.length > requestLimit) {
        throw new Error(RequestLimitMessage);
      }
      return Promise.race([...promises, requestWithTimeout(request, promises)]);
    })
    .then((resp) => resp);

  return result;
}
about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!