Axios: Adicionando Parâmetro de Repetição

Criado em 27 nov. 2015  ·  23Comentários  ·  Fonte: axios/axios

Tenho uma API que retorna de vez em quando ECONNRESET . Então, eu gostaria de fazer uma nova tentativa em tal erro. Você tem planos de adicionar o recurso retry a esta biblioteca?

Comentários muito úteis

@mericsson Também estou precisando de um backoff exponencial ao tentar novamente. Eu juntei o seguinte, o que funciona muito bem. Você pode querer adicionar a verificação de erros / códigos de status específicos, pois isso atualmente apenas intercepta e tenta novamente todos os erros.

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);
    });

Opções de configuração:
retry - Número de vezes para repetir a solicitação após a primeira solicitação com falha.
retryDelay - Número de milissegundos de espera entre as solicitações com falha (o padrão é 1).

Posso tornar isso um pouco mais configurável em algum ponto.

Todos 23 comentários

alguma atualização disso?

Eu acho que isso é muito importante. O cenário pode ser quando implementamos Axios para web móvel, então o usuário muda a fonte de internet de WiFi para qualquer tipo de conexão móvel.

Não acho que esse tipo de funcionalidade deva estar nesta biblioteca. Se você precisar disso, pode criar um interceptor para isso.

@jtangelder alguma ideia de como deveria ser?

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 assim! Ele tenta novamente 500 erros uma vez.

Eu concordo com @jtangelder que isso não pertence à biblioteca principal. Este é um ótimo caso de uso para interceptores, conforme ilustrado.

@jtangelder @mzabriskie obrigado! na verdade, é um ótimo exemplo para documentação também

1 Gostaria que este exemplo fosse mais fácil de encontrar!

@jtangelder muito obrigado pelo snippet

Uma pequena correção no snippet, acho que o status de erro retornado deve ser 504 em vez de 500.

@jtangelder exemplo muito útil.

Estou pensando, alguma ideia sobre como fazer algo com recuo exponencial? É possível retornar uma promessa de retryFailedRequest ? Ou outras sugestões? Obrigado!

O exemplo em @jtangelder deve ser incluído na página do livro de receitas

Agora você pode usar axios-retry para isso.

Eu concordo. Isso realmente deve ser parte da biblioteca, ou pelo menos melhor documentado.

@mericsson Também estou precisando de um backoff exponencial ao tentar novamente. Eu juntei o seguinte, o que funciona muito bem. Você pode querer adicionar a verificação de erros / códigos de status específicos, pois isso atualmente apenas intercepta e tenta novamente todos os erros.

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);
    });

Opções de configuração:
retry - Número de vezes para repetir a solicitação após a primeira solicitação com falha.
retryDelay - Número de milissegundos de espera entre as solicitações com falha (o padrão é 1).

Posso tornar isso um pouco mais configurável em algum ponto.

@KyleRoss Obrigado pelo código, fiz um ajuste para que as tentativas sejam exponenciais

// 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 Obrigado por compartilhar.

O atraso pode ser definido cada vez mais:

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

Se quiser repetir uma solicitação 4xx ou 5xx, você precisa trabalhar com o objeto de erro desta forma:

Para interceptar seus pedidos:

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 suas respostas:

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

Idéias incríveis. Enrolei uma boa parte disso em um módulo npm, se as pessoas estiverem interessadas:
https://github.com/JustinBeckwith/retry-axios

Fico feliz em receber solicitações de recursos ✨

axios-retry vs retry-axios

@KyleRoss Tentei adicionar as opções de configuração retry e retryDelay ao AxiosRequestConfig, mas não parece que elas existem. Como você fez isso funcionar?

@lawloretienne você precisa certificar-se de adicionar o código no meu exemplo antes de usar qualquer um dos parâmetros de nova tentativa. Uma vez que atua mais como um plugin, as novas propriedades não são documentadas como parte do próprio axios.

config.__retryCount = config.__retryCount || 0;

@KyleRoss Incapaz de passar config config, cada 'config .__ reyCount' é indefinido.
https://github.com/axios/axios/blob/v0.19.0/lib/core/mergeConfig.js
Propriedades personalizadas agora são filtradas.

As configurações personalizadas de

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

@mericsson Também estou precisando de um backoff exponencial ao tentar novamente. Eu juntei o seguinte, o que funciona muito bem. Você pode querer adicionar a verificação de erros / códigos de status específicos, pois isso atualmente apenas intercepta e tenta novamente todos os erros.

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);
    });

Opções de configuração:
retry - Número de vezes para repetir a solicitação após a primeira solicitação com falha.
retryDelay - Número de milissegundos de espera entre as solicitações com falha (o padrão é 1).

Posso tornar isso um pouco mais configurável em algum ponto.

obrigado pela ajuda!

Esta página foi útil?
0 / 5 - 0 avaliações