Skip to content
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

Axios race condition with cancel token? #4042

Closed
9mm opened this issue Sep 10, 2021 · 1 comment
Closed

Axios race condition with cancel token? #4042

9mm opened this issue Sep 10, 2021 · 1 comment

Comments

@9mm
Copy link

9mm commented Sep 10, 2021

Describe the issue

I'm using axios in the browser.

Cancel token exceptions do not appear to correspond 100% with what Chrome developer tools considers a response failure.

Essentially I want to retry certain requests (even POST requests) if the server doesn't respond within 5000ms. Obviously with non-idempotent requests it's important that success/failure of response matches the server.

So I tried to implement a connection timeout using the following code. A more simple version of this code is here, and it has the same problem.

I noticed that if I set the connection timeout to be as close as possible to the time it takes for server to respond (to emulate a request finishing right at the time out), there appears to be a race condition where cancel is retried even though it was successful

I have tried axios-retry and it has the same issue.

Example Code

const makeRequest = async (args, connTimeout, responseTimeout) => {
  const source = axios.CancelToken.source();

  const argsWithToken = {
    ...args,
    cancelToken: source.token,
  };

  const api = buildAxios(responseTimeout);

  const timeout = setTimeout(source.cancel, connTimeout);

  return api(argsWithToken).then(result => {
    clearTimeout(timeout);
    return result;
  });
};

const handleRetries = (args, maxRetries) => (
  new Promise(async (resolve, reject) => { /* eslint-disable-line */
    let retries = 0;
    let success = false;

    while (!success && retries < maxRetries) {
      try {
        const result = await makeRequest(args, 300, 30000); /* eslint-disable-line */
        success = true;
        resolve(result);
      } catch (err) {
        retries += 1;
        // console.log(`Error making ${args.method} request to ${args.url}, retrying... #${retries}`);
      }
    }
    // line below is included to prevent process leaks
    if (!success) reject(new Error(`Retried ${retries} times and still failed: ${args.url}`));
  })
);

handleRetries({url: '/settings', method: 'get'}, 3)

Expected behavior, if applicable

I don't know if it's my code, a limitation of JS, or axios, but I would expect that cancel would never get called, as the timeout is cleared in the success callback.

Environment

  • Axios Version: ^0.21.1
  • Browser Chrome
  • Browser latest
  • OS: latest OSX
  • Additional Library Versions Vue 3
@github-actions
Copy link
Contributor

Hello! 👋

This issue is being automatically closed because it does not follow the issue template. Please read the issue template carefully and follow all of the instructions when opening a new issue.

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant