-1

I'm trying to setup a queuing system such that a post request is repeated n times, at intervals of i. Ideally I'd like to wrap this all in a single promise, so the whole thing can be asynchronous.

So far I have this, which feels somewhat messy and hacky. I feel like I may be missing a much easier solution, but I can't seem to find anything:

// this is mocked to avoid a wall of code
const postData = (url, data) => Promise.resolve(true);

// this is mocked to avoid a wall of code
const resIsFailed = () => true;

const requestChain = ({
  url,
  data,
  maxRequests,
  requestTimeout,
  currentRequest = 0,
  requestIncrement = increment => increment,
}) => {

  // exit condition
  if (currentRequest >= maxRequests || (!maxRequests)) {
    console.log('Too many failed requests');
    return Promise.reject(new Error('Too many attempts'));
  }

  // post the data, if it fails, try again
  postData(
    url,
    data,
  ).then(res => {
  
    if (resIsFailed(res)) {
    
      console.log('Failed response: ');
      console.dir(res);
      
      setTimeout(() => {
        requestChain({
          url,
          data,
          maxRequests,
          requestTimeout: requestIncrement(requestTimeout),
          currentRequest: currentRequest + 1,
          requestIncrement,
        });
      }, requestTimeout);
      
    } else {
    
      return Promise.resolve(res);
      
    }
  });
}

requestChain({
  url: 'fail',
  data: {},
  maxRequests: 5,
  requestTimeout: 100,
})
OliverRadini
  • 6,238
  • 1
  • 21
  • 46
  • check out [async/await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) – Meirion Hughes Aug 20 '18 at 13:05
  • You should promisify `setTimeout` and properly chain the promises, but otherwise this looks fine – Bergi Aug 20 '18 at 13:09
  • What exactly do you think looks messy? – Bergi Aug 20 '18 at 13:10
  • @Bergi I think you're right about `setTimout` needing to be promisified. I'm currently working on switching this to `async`/`await` as I think it'll look nicer – OliverRadini Aug 20 '18 at 13:37
  • @OliverRadini, in addition to promisifying the setTimeout, you can simplify `return Promise.resolve(res);` to `return res;`. From a then callback, you can return a value; it doesn't need to be promise-wrapped. – Roamer-1888 Aug 20 '18 at 15:20

1 Answers1

-2

The async library is super helpful to control all kind of async chaining etc. You might want to have a look at async.retry. It should give you the exact behaviour.

Moritz Herbert
  • 401
  • 1
  • 4
  • 8
  • Thanks, I'll take a look at this – OliverRadini Aug 20 '18 at 13:07
  • The async.js library is callback-based and super useless when dealing with promise code. – Bergi Aug 20 '18 at 13:07
  • @Bergi You are right about that. Nevertheless it solves the problem. If you still need a promise to be returned, just create one and resolve/reject it in the callbacks of async.retry. – Moritz Herbert Aug 20 '18 at 13:12
  • @MoritzHerbert That would be much more ugly (and errorprone) than what the OP currently has. Also `async.retry` doesn't seem to support `requestIncrement` – Bergi Aug 20 '18 at 13:22