Code Monkey home page Code Monkey logo

Comments (5)

dalwlad avatar dalwlad commented on July 22, 2024 1

@elbywan Thanks for that. It works indeed!

from wretch.

elbywan avatar elbywan commented on July 22, 2024

Hi @dalwlad !

You can indeed do that using a middleware, but if you need to retry a request on 401/403 (or any other error) you can also use catchers which should be easier.
I wrote an example of doing this in the following issue or in the docs.

And if you still need to use middlewares for this, I can post a code sample later today or tomorrow !

from wretch.

dalwlad avatar dalwlad commented on July 22, 2024

Thanks for the quick reply @elbywan. I've seen the example for how to use the catchers for this and they work just fine. But if you would need to implement the retry mechanism for any call that is hitting the api, that would become tedious. The use case I'm working right now has a requirement like : for all outgoing requests, there should be a retry mechanism, ideally indefinite, but the delay should be detemined by some sort of exponential function, with capping values: for example start at 100ms and increase it, but no more than 1000ms. In other words, you receive an error for a request, wait 100ms and try again, Next time, if you still receive the error, increase the timeout and try again ... you got the idea.

I was trying something like below, but got stuck on the resolve part where for the second attempt, it fails because the wretch call doesn't have any rejection handling.

const DEFAULTS = {
  ERROR_CODES : []
};

const reconnectMiddleware = ({
  errorCodes = DEFAULTS.ERROR_CODES
} = {}) => {
  const tracker = new Map();

  errorCodes.map(code => {
    tracker.set(code, new Map());
  });

  return next => (url, options) => {
    const req = next(url, options);

    req.then(response => {
      if (tracker.has(response.status)) {
        if (!response.ok) {
          const requestKey = `${options.method}@${url}`;
          const numberOfAttemptsMade = tracker.get(response.status).get(requestKey) || 0;

          tracker.get(response.status).set(requestKey, numberOfAttemptsMade + 1);

          return new Promise(resolve => {
            const delay = Math.max(DEFAULTS.DELAY * numberOfAttemptsMade, 1000);

            setTimeout(() => {
              resolve(wretch(url)[options.method.toLowerCase()](options));
            }, delay);
          });
        }

        tracker.set(response.status, new Map());
      }

      return response;
    });

    req.catch(response => {
      const requestKey = `${options.method}@${url}`;
      const numberOfAttemptsMade = tracker.get(response.status).get(requestKey) || 0;

      tracker.get(response.status).set(requestKey, numberOfAttemptsMade + 1);

      return new Promise(resolve => {
        const delay = Math.max(DEFAULTS.DELAY * numberOfAttemptsMade, 1000);

        setTimeout(() => {
          resolve(wretch(url)[options.method.toLowerCase()](options));
        }, delay);
      });
    });

    return req;
  };
};

export default reconnectMiddleware;

from wretch.

elbywan avatar elbywan commented on July 22, 2024

@dalwlad Just made some corrections to your snippet, can you check with the code below ? I'm pretty sure it should work 😉 .

const DEFAULTS = {
  DELAY: 100,
  MAX_ATTEMPTS: 10,
  ERROR_CODES : []
};

const reconnectMiddleware = ({
  errorCodes = DEFAULTS.ERROR_CODES
} = {}) => {
  const tracker = new Map();

  errorCodes.map(code => {
    tracker.set(code, new Map());
  });

  return next => (url, options) => {
    const checkStatus = (response) => {
        if (tracker.has(response.status)) {
            if (!response.ok) {
                const requestKey = `${options.method}@${url}`;
                const numberOfAttemptsMade = tracker.get(response.status).get(requestKey) || 0;
                tracker.get(response.status).set(requestKey, numberOfAttemptsMade + 1);

                // Maybe add a maximum number of attempts ?
                if(numberOfAttemptsMade >= MAX_ATTEMPTS) 
                    return response

                // We need to recurse until we have a correct response and chain the checks
                return new Promise(resolve => {
                    const delay = Math.min(DEFAULTS.DELAY * numberOfAttemptsMade, 1000);
                    setTimeout(() => {
                        resolve(next(url, options));
                    }, delay);
                }).then(checkStatus);
            }

            // If ok - reset the map and return the response
            tracker.set(response.status, new Map());
            return Promise.resolve(response);
        }
        return response
    }
    // Willingly omitted .catch which prevents handling network errors and should throw
    return next(url, options).then(checkStatus);
  };
};

from wretch.

elbywan avatar elbywan commented on July 22, 2024

Great ! Closing the issue then !

from wretch.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.