Axios: Agregar parámetro de reintento

Creado en 27 nov. 2015  ·  23Comentarios  ·  Fuente: axios/axios

Tengo una API que de vez en cuando devuelve ECONNRESET . Así que me gustaría volver a intentarlo con ese error. ¿Tiene planes de agregar la función retry a esta biblioteca?

Comentario más útil

@mericsson También necesito un retroceso exponencial cuando vuelvo a intentarlo. He reunido lo siguiente que funciona muy bien. Es posible que desee agregar la verificación de errores / códigos de estado específicos, ya que actualmente solo intercepta y reintenta todos los errores.

axios.interceptors.response.use(undefined, function axiosRetryInterceptor(err) {
    var config = err.config;
    // If config does not exist or the retry option is not set, reject
    if(!config || !config.retry) return Promise.reject(err);

    // Set the variable for keeping track of the retry count
    config.__retryCount = config.__retryCount || 0;

    // Check if we've maxed out the total number of retries
    if(config.__retryCount >= config.retry) {
        // Reject with the error
        return Promise.reject(err);
    }

    // Increase the retry count
    config.__retryCount += 1;

    // Create new promise to handle exponential backoff
    var backoff = new Promise(function(resolve) {
        setTimeout(function() {
            resolve();
        }, config.retryDelay || 1);
    });

    // Return the promise in which recalls axios to retry the request
    return backoff.then(function() {
        return axios(config);
    });
});

Usar:

axios.get('/some/endpoint', { retry: 5, retryDelay: 1000 })
    .then(function(res) {
        console.log('success', res.data);
    })
    .catch(function(err) {
        console.log('failed', err);
    });

Opciones de configuración:
retry : número de veces que se reintentará la solicitud después de la primera solicitud fallida.
retryDelay - Número de milisegundos de espera entre solicitudes fallidas (el valor predeterminado es 1).

Puedo hacer esto un poco más configurable en esencia en algún momento.

Todos 23 comentarios

¿Algún avance en esto?

Yo pienso que esto es muy importante. El escenario tal vez cuando implementemos Axios para la web móvil, luego el usuario cambie la fuente de Internet de WiFi a cualquier tipo de conexión móvil.

No creo que este tipo de funcionalidad deba estar en esta biblioteca. Si lo necesita, puede crear un interceptor para esto.

@jtangelder alguna idea de cómo debería verse?

function retryFailedRequest (err) {
  if (err.status === 500 && err.config && !err.config.__isRetryRequest) {
    err.config.__isRetryRequest = true;
    return axios(err.config);
  }
  throw err;
}
axios.interceptors.response.use(undefined, retryFailedRequest);

¡Algo como esto! Vuelve a intentar 500 errores una vez.

Estoy de acuerdo con @jtangelder en que esto no pertenece a la biblioteca principal. Este es un gran caso de uso para interceptores como se ilustra.

@jtangelder @mzabriskie ¡gracias! en realidad, también es un gran ejemplo para la documentación.

+1 ¡Ojalá este ejemplo fuera más fácil de encontrar!

@jtangelder muchas gracias por el fragmento

Una pequeña corrección en el fragmento, creo que el estado de error devuelto debería ser 504 en lugar de 500.

@jtangelder ejemplo muy útil.

Me pregunto, ¿alguna idea sobre cómo hacer algo con un retroceso exponencial? ¿Es posible devolver una promesa desde retryFailedRequest ? ¿O otras sugerencias? ¡Gracias!

El ejemplo en @jtangelder debe incluirse en la página del libro de recetas

Ahora puede usar axios-retry para esto.

Estoy de acuerdo. Esto realmente debería ser parte de la biblioteca, o al menos estar mejor documentado.

@mericsson También necesito un retroceso exponencial cuando vuelvo a intentarlo. He reunido lo siguiente que funciona muy bien. Es posible que desee agregar la verificación de errores / códigos de estado específicos, ya que actualmente solo intercepta y reintenta todos los errores.

axios.interceptors.response.use(undefined, function axiosRetryInterceptor(err) {
    var config = err.config;
    // If config does not exist or the retry option is not set, reject
    if(!config || !config.retry) return Promise.reject(err);

    // Set the variable for keeping track of the retry count
    config.__retryCount = config.__retryCount || 0;

    // Check if we've maxed out the total number of retries
    if(config.__retryCount >= config.retry) {
        // Reject with the error
        return Promise.reject(err);
    }

    // Increase the retry count
    config.__retryCount += 1;

    // Create new promise to handle exponential backoff
    var backoff = new Promise(function(resolve) {
        setTimeout(function() {
            resolve();
        }, config.retryDelay || 1);
    });

    // Return the promise in which recalls axios to retry the request
    return backoff.then(function() {
        return axios(config);
    });
});

Usar:

axios.get('/some/endpoint', { retry: 5, retryDelay: 1000 })
    .then(function(res) {
        console.log('success', res.data);
    })
    .catch(function(err) {
        console.log('failed', err);
    });

Opciones de configuración:
retry : número de veces que se reintentará la solicitud después de la primera solicitud fallida.
retryDelay - Número de milisegundos de espera entre solicitudes fallidas (el valor predeterminado es 1).

Puedo hacer esto un poco más configurable en esencia en algún momento.

@KyleRoss Gracias por el código, hice un ajuste para que los reintentos fueran exponenciales

// Create new promise to handle exponential backoff. formula (2^c - 1 / 2) * 1000(for mS to seconds)
    const backOffDelay = config.retryDelay 
        ? ( (1/2) * (Math.pow(2, config.__retryCount) - 1) ) * 1000
        : 1;

    const backoff = new Promise((resolve) => {
        setTimeout(() => {
            resolve();
        },  backOffDelay);
    });

@KyleRoss Gracias por compartir.

El retraso se puede configurar cada vez más:

const RETRY_TIMEOUTS = [1, 3, 5, 10]; // seconds
const delay = RETRY_TIMEOUTS[config.retryCount] * 1000;

Si desea volver a intentar una solicitud 4xx o 5xx, necesita trabajar con el objeto de error de esa manera:

Para interceptar sus solicitudes:

axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });

Para interceptar sus respuestas:

axios.interceptors.response.use(function (response) {
    // Do something with response data
    return response;
  }, function (error) {
    // Do something with response error
    return Promise.reject(error);
  });

Ideas asombrosas. Reuní un poco de esto en un módulo npm, si la gente está interesada:
https://github.com/JustinBeckwith/retry-axios

Feliz de aceptar solicitudes de funciones ✨

axios-retry frente a retry-axios

@KyleRoss Intenté agregar las opciones de configuración reintentar y reintentarDelay a AxiosRequestConfig pero no parece que existan. ¿Cómo conseguiste que funcionara?

@lawloretienne necesita asegurarse de agregar el código en mi ejemplo antes de usar cualquiera de los parámetros de reintento. Dado que actúa más como un complemento, las nuevas propiedades no están documentadas como parte de axios en sí.

config.__retryCount = config.__retryCount || 0;

@KyleRoss No se puede pasar la configuración de configuración, cada 'config .__ reyCount' no está definido.
https://github.com/axios/axios/blob/v0.19.0/lib/core/mergeConfig.js
Las propiedades personalizadas ahora se filtran.

La configuración personalizada de

axios.defaults.headers.common['retry'] = 3
axios.defaults.headers.common['retryDelay'] = 1000
axios.defaults.headers.common['retryCount'] = 0

@mericsson También necesito un retroceso exponencial cuando vuelvo a intentarlo. He reunido lo siguiente que funciona muy bien. Es posible que desee agregar la verificación de errores / códigos de estado específicos, ya que actualmente solo intercepta y reintenta todos los errores.

axios.interceptors.response.use(undefined, function axiosRetryInterceptor(err) {
    var config = err.config;
    // If config does not exist or the retry option is not set, reject
    if(!config || !config.retry) return Promise.reject(err);

    // Set the variable for keeping track of the retry count
    config.__retryCount = config.__retryCount || 0;

    // Check if we've maxed out the total number of retries
    if(config.__retryCount >= config.retry) {
        // Reject with the error
        return Promise.reject(err);
    }

    // Increase the retry count
    config.__retryCount += 1;

    // Create new promise to handle exponential backoff
    var backoff = new Promise(function(resolve) {
        setTimeout(function() {
            resolve();
        }, config.retryDelay || 1);
    });

    // Return the promise in which recalls axios to retry the request
    return backoff.then(function() {
        return axios(config);
    });
});

Usar:

axios.get('/some/endpoint', { retry: 5, retryDelay: 1000 })
    .then(function(res) {
        console.log('success', res.data);
    })
    .catch(function(err) {
        console.log('failed', err);
    });

Opciones de configuración:
retry : número de veces que se reintentará la solicitud después de la primera solicitud fallida.
retryDelay - Número de milisegundos de espera entre solicitudes fallidas (el valor predeterminado es 1).

Puedo hacer esto un poco más configurable en esencia en algún momento.

¡gracias por la ayuda!

¿Fue útil esta página
0 / 5 - 0 calificaciones