retry-axios icon indicating copy to clipboard operation
retry-axios copied to clipboard

I set retry 3 times,but only retry 1 times

Open CatcherRao opened this issue 4 years ago • 9 comments

raxConfig: {
    retry: 3,
    noResponseRetries: 5,
    instance: http,
    retryDelay: 100,
    httpMethodsToRetry: ['GET', 'OPTIONS', 'POST'],
    shouldResetTimeout: false,
    onRetryAttempt: (err) => {
      const cfg = rax.getConfig(err);
      console.log(cfg.currentRetryAttempt);
    }
  }

CatcherRao avatar Sep 29 '19 03:09 CatcherRao

Is the axios instance being shared? I ran into a similar issue and found that the retry counter is shared between multiple uses of a single instance.

Possibly related to #61

tehaksbrid avatar Dec 04 '19 15:12 tehaksbrid

Greetings! Can you share a complete code example that does this? We have tests specifically covering number of retries, so an isolated example of how to break it would be super helpful.

JustinBeckwith avatar Jan 11 '20 19:01 JustinBeckwith

@JustinBeckwith was that WRT my comment? I assumed #61 was well-known. Wanted to confirm before I spent time making a clear example.

Also, thank you for the awesome tool. I use it in every lambda project.

tehaksbrid avatar Jan 11 '20 23:01 tehaksbrid

Hello @JustinBeckwith, thanks for the library.

Here is a reproducible demo for you: https://github.com/tomic-dvica-golf/retry-axios-demo/tree/master

just run yarn test. hope you find it useful!

dvicagolf avatar Jan 20 '20 23:01 dvicagolf

Note that #61 was fixed, so this issue is probably also fixed.

yoshigev avatar Mar 23 '20 09:03 yoshigev

Sweet. Could I trouble anyone to try it and take a look?

JustinBeckwith avatar Mar 23 '20 13:03 JustinBeckwith

Hi @JustinBeckwith, I ran into the same issue where I have specified both retry count and noResponseRetries to 3.

I have debugged the "retry-axios" code and turns out that during the first initial request raxConfig received the correct value of httpMethodsToRetry & statusCodesToRetry i.e Array which I have passed from my code as config.

But when an error occurred for first time, The response interceptor is being called with correct raxConfig and in that shouldRetryRequest is called which returns true to retry the 1st attempt of the request.

Now, in this 1st attempt of retry, The response interceptor receives the incorrect raxConfig i.e the value of httpMethodsToRetry & statusCodesToRetry is Object this time but not Array therefore when normalizeArray is called from response interceptor it receives Object and return empty Array hence shouldRetryRequest function return false as the condition config.httpMethodsToRetry.indexOf(err.config.method.toUpperCase()) < 0 evaluates to true.

Please find the attached screenshots for a better understanding.

This is the Initial raxConfig when the first-time error occurred which in my case is timeout. First time error - rax config

Now this is the raxConfig for 1st retry attempt and error occurred, Here you can clearly see the value of httpMethodsToRetry & statusCodesToRetry is Object this time but not Array. therefore normalizeArray return empty Array Second time error - rax config

now for this error when shouldRetryRequest function called see the config now. Should retry method rax config

therefore config.httpMethodsToRetry.indexOf(err.config.method.toUpperCase()) < 0 evaluates to true and 2nd retry won't happen.

Please look into the issue, I'm stuck in some very important project or allow me to debug this furthermore, let see if I can find a cause from where Array is turning into Object Thanks.

morevolk-latei avatar Mar 31 '20 08:03 morevolk-latei

@JustinBeckwith I have setup a small environment on Repl.it to test it. Here https://repl.it/@seahindeniz/RaxRetryingIssue

seahindeniz avatar Mar 31 '20 09:03 seahindeniz

According to the printouts from @morevolk-latei, the keys in the object form are now strings instead of integers.

If so, the fix can be pretty simple - just replace

      if (typeof key === 'number') {
        arr[key] = obj[key];
      }

with

      const idx = parseInt(key, 10);
      if (!isNaN(idx)) {
        arr[idx] = obj[key];
      }

khitrenovich avatar Jun 17 '20 14:06 khitrenovich

Here is a full example for timeout error:

import axios from 'axios';
import * as rax from 'retry-axios';

const axiosConf = {
  timeout: 1000,
  raxConfig: {
    retry: 3,
    noResponseRetries: 3,
    httpMethodsToRetry: ['POST'],
    onRetryAttempt: (err) => {
      const cfg = rax.getConfig(err);
      console.log(`Retry attempt #${cfg?.currentRetryAttempt} (after ${err.code} for URL ${err.config?.url})`);
    }
  }
};

try {
  const axiosClient = axios.create();
  rax.attach(axiosClient);
  const res = await axiosClient.post('http://httpbin.org/delay/2', {}, axiosConf);
  console.log(res.data);
} catch (err) {
  console.error(err.message);
}

Output:

Retry attempt #1 (after ECONNABORTED for URL http://httpbin.org/delay/2)
timeout of 1000ms exceeded

orgads avatar Nov 15 '23 12:11 orgads

Here is a simple example with error code:

import axios from 'axios';
import * as rax from 'retry-axios';

try {
  const axiosClient = axios.create();
  rax.attach(axiosClient);
  console.log('Sending request');
  const res = await axiosClient.get('http://httpbin.org/status/503', {
    raxConfig: {
      retry: 3,
      noResponseRetries: 3,
      onRetryAttempt: (err) => {
        const cfg = rax.getConfig(err);
        console.log(`Retry attempt #${cfg?.currentRetryAttempt} (after ${err.code} for URL ${err.config?.url})`);
      }
    }
  });
  console.log(res.data);
} catch (err) {
  console.log(err.message);
}

Output:

Sending request
Retry attempt #1 (after ERR_BAD_RESPONSE for URL http://httpbin.org/status/503)
Request failed with status code 503

orgads avatar Nov 15 '23 14:11 orgads

:tada: This issue has been resolved in version 3.1.2 :tada:

The release is available on:

Your semantic-release bot :package::rocket:

github-actions[bot] avatar Nov 16 '23 19:11 github-actions[bot]