-
-
Notifications
You must be signed in to change notification settings - Fork 99
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Retry mechanism #16
Comments
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. And if you still need to use middlewares for this, I can post a code sample later today or tomorrow ! |
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; |
@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);
};
}; |
@elbywan Thanks for that. It works indeed! |
Great ! Closing the issue then ! |
I've just started using wretch and noticed the nice feature that allows adding custom middlewares for implementing cross-cutting concerns like caching, as you've nicely illustrated in the docs. Many times, there is a need for adding support for retry mechanism. Would it be possible to illustrate in a sample how a request retry middleware would look like?
The text was updated successfully, but these errors were encountered: