Axios: μž¬μ‹œλ„ λ§€κ°œλ³€μˆ˜ μΆ”κ°€

에 λ§Œλ“  2015λ…„ 11μ›” 27일  Β·  23μ½”λ©˜νŠΈ  Β·  좜처: axios/axios

λ•Œλ•Œλ‘œ ECONNRESET λ°˜ν™˜ν•˜λŠ” APIκ°€ ν•˜λ‚˜ μžˆμŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ λ‚˜λŠ” κ·ΈλŸ¬ν•œ 였λ₯˜μ— λŒ€ν•΄ λ‹€μ‹œ μ‹œλ„ν•˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€. 이 λΌμ΄λΈŒλŸ¬λ¦¬μ— retry κΈ°λŠ₯을 μΆ”κ°€ν•  κ³„νšμ΄ μžˆμŠ΅λ‹ˆκΉŒ?

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

@mericsson μž¬μ‹œλ„ν•  λ•Œ μ§€μˆ˜ λ°±μ˜€ν”„κ°€ λ„ˆλ¬΄ ν•„μš”ν•©λ‹ˆλ‹€. λ‚˜λŠ” λ‹€μŒκ³Ό 같이 ν›Œλ₯­ν•˜κ²Œ μž‘λ™ν•©λ‹ˆλ‹€. 이것은 ν˜„μž¬ λͺ¨λ“  였λ₯˜λ₯Ό κ°€λ‘œμ±„κ³  μž¬μ‹œλ„ν•˜κΈ° λ•Œλ¬Έμ— νŠΉμ • 였λ₯˜/μƒνƒœ μ½”λ“œλ₯Ό ν™•μΈν•˜λŠ” 데 μΆ”κ°€ν•˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€.

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

μ‚¬μš©:

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

ꡬ성 μ˜΅μ…˜:
retry - 첫 번째 μ‹€νŒ¨ν•œ μš”μ²­ ν›„ μš”μ²­μ„ μž¬μ‹œλ„ν•˜λŠ” νšŸμˆ˜μž…λ‹ˆλ‹€.
retryDelay - μ‹€νŒ¨ν•œ μš”μ²­ μ‚¬μ΄μ˜ λŒ€κΈ° μ‹œκ°„(λ°€λ¦¬μ΄ˆ)μž…λ‹ˆλ‹€(기본값은 1).

μ–΄λŠ μ‹œμ μ—μ„œ μš”μ μ—μ„œ 이것을 μ’€ 더 ꡬ성 κ°€λŠ₯ν•˜κ²Œ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.

λͺ¨λ“  23 λŒ“κΈ€

이것에 λŒ€ν•œ μ–΄λ–€ μ—…λ°μ΄νŠΈ?

μ €λŠ” 이것이 맀우 μ€‘μš”ν•˜λ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€. μ‹œλ‚˜λ¦¬μ˜€λŠ” μš°λ¦¬κ°€ λͺ¨λ°”일 μ›Ήμš© Axiosλ₯Ό κ΅¬ν˜„ν•  λ•Œ μ‚¬μš©μžκ°€ 인터넷 μ†ŒμŠ€λ₯Ό WiFiμ—μ„œ λͺ¨λ“  μ’…λ₯˜μ˜ λͺ¨λ°”일 μ—°κ²°λ‘œ μ „ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ‚˜λŠ” 이런 μ’…λ₯˜μ˜ κΈ°λŠ₯이 이 λΌμ΄λΈŒλŸ¬λ¦¬μ— μžˆμ–΄μ„œλŠ” μ•ˆ λœλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€. ν•„μš”ν•œ 경우 이λ₯Ό μœ„ν•œ 인터셉터λ₯Ό λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.

@jtangelder μ–΄λ–€ 아이디어가 μ–΄λ–»κ²Œ μƒκ²ΌμŠ΅λ‹ˆκΉŒ?

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

이 같은! 500 였λ₯˜λ₯Ό ν•œ 번 μž¬μ‹œλ„ν•©λ‹ˆλ‹€.

λ‚˜λŠ” 이것이 핡심 λΌμ΄λΈŒλŸ¬λ¦¬μ— μ†ν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” @jtangelder의 말에 λ™μ˜ν•©λ‹ˆλ‹€. 이것은 κ·Έλ¦Όκ³Ό 같이 μΈν„°μ…‰ν„°μ˜ ν›Œλ₯­ν•œ μ‚¬μš© μ‚¬λ‘€μž…λ‹ˆλ‹€.

@jtangelder @mzabriskie κ°μ‚¬ν•©λ‹ˆλ‹€! μ‹€μ œλ‘œ λ¬Έμ„œν™”μ—λ„ 쒋은 μ˜ˆμž…λ‹ˆλ‹€.

+1 이 μ˜ˆμ œκ°€ 더 μ°ΎκΈ° μ‰¬μ› μœΌλ©΄ μ’‹κ² μŠ΅λ‹ˆλ‹€!

@jtangelder 슀 λ‹ˆνŽ«μ„ μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€.

슀 λ‹ˆνŽ«μ„ μ•½κ°„ μˆ˜μ •ν•˜λ©΄ λ°˜ν™˜ 된 였λ₯˜ μƒνƒœκ°€ 500 λŒ€μ‹  504κ°€λ˜μ–΄μ•Όν•œλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€.

@jtangelder 맀우 μœ μš©ν•œ μ˜ˆμž…λ‹ˆλ‹€.

μ§€μˆ˜ λ°±μ˜€ν”„λ‘œ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 방법에 λŒ€ν•œ 아이디어가 μžˆλŠ”μ§€ κΆκΈˆν•©λ‹ˆλ‹€. retryFailedRequest μ—μ„œ 약속을 λ°˜ν™˜ν•  수 μžˆμŠ΅λ‹ˆκΉŒ? λ˜λŠ” λ‹€λ₯Έ μ œμ•ˆ? 감사 ν•΄μš”!

@jtangelder 의 μ˜ˆμ œλŠ” μš”λ¦¬μ±… νŽ˜μ΄μ§€μ— ν¬ν•¨λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.

이제 이λ₯Ό μœ„ν•΄ axios-retry λ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ‚˜λŠ” λ™μ˜ν•œλ‹€. 이것은 μ‹€μ œλ‘œ 라이브러리의 μΌλΆ€μ΄κ±°λ‚˜ 적어도 더 잘 λ¬Έμ„œν™”λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.

@mericsson μž¬μ‹œλ„ν•  λ•Œ μ§€μˆ˜ λ°±μ˜€ν”„κ°€ λ„ˆλ¬΄ ν•„μš”ν•©λ‹ˆλ‹€. λ‚˜λŠ” λ‹€μŒκ³Ό 같이 ν›Œλ₯­ν•˜κ²Œ μž‘λ™ν•©λ‹ˆλ‹€. 이것은 ν˜„μž¬ λͺ¨λ“  였λ₯˜λ₯Ό κ°€λ‘œμ±„κ³  μž¬μ‹œλ„ν•˜κΈ° λ•Œλ¬Έμ— νŠΉμ • 였λ₯˜/μƒνƒœ μ½”λ“œλ₯Ό ν™•μΈν•˜λŠ” 데 μΆ”κ°€ν•˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€.

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

μ‚¬μš©:

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

ꡬ성 μ˜΅μ…˜:
retry - 첫 번째 μ‹€νŒ¨ν•œ μš”μ²­ ν›„ μš”μ²­μ„ μž¬μ‹œλ„ν•˜λŠ” νšŸμˆ˜μž…λ‹ˆλ‹€.
retryDelay - μ‹€νŒ¨ν•œ μš”μ²­ μ‚¬μ΄μ˜ λŒ€κΈ° μ‹œκ°„(λ°€λ¦¬μ΄ˆ)μž…λ‹ˆλ‹€(기본값은 1).

μ–΄λŠ μ‹œμ μ—μ„œ μš”μ μ—μ„œ 이것을 μ’€ 더 ꡬ성 κ°€λŠ₯ν•˜κ²Œ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.

@KyleRoss μ½”λ“œ κ°μ‚¬ν•©λ‹ˆλ‹€. μž¬μ‹œλ„λ₯Ό κΈ°ν•˜κΈ‰μˆ˜μ μœΌλ‘œ μ‘°μ •ν–ˆμŠ΅λ‹ˆλ‹€.

// 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 κ³΅μœ ν•΄ μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€.

지연을 점점 더 μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

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

4xx λ˜λŠ” 5xx μš”μ²­μ„ λ‹€μ‹œ μ‹œλ„ν•˜λ €λ©΄ λ‹€μŒκ³Ό 같은 였λ₯˜ κ°œμ²΄μ— λŒ€ν•œ μž‘μ—…μ΄ ν•„μš”ν•©λ‹ˆλ‹€.

μš”μ²­μ„ κ°€λ‘œμ±„λ €λ©΄:

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

응닡을 κ°€λ‘œμ±„λ €λ©΄:

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

멋진 아이디어. μ‚¬λžŒλ“€μ΄ 관심이 μžˆλ‹€λ©΄, λ‚˜λŠ” 이것을 npm λͺ¨λ“ˆμ— κ½€ 많이 λ„£μ—ˆμŠ΅λ‹ˆλ‹€.
https://github.com/JustinBeckwith/retry-axios

κΈ°λŠ₯ μš”μ²­μ„ μˆ˜λ½ν•˜κ²Œ λ˜μ–΄ κΈ°μ©λ‹ˆλ‹€ ✨

axios-retry λŒ€ retry-axios

@KyleRoss AxiosRequestConfig 에 retry 및 retryDelay ꡬ성 μ˜΅μ…˜μ„ μΆ”κ°€ν•˜λ €κ³  μ‹œλ„ν–ˆμ§€λ§Œ μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€. μ–΄λ–»κ²Œ μž‘λ™μ‹œν‚€μ…¨λ‚˜μš”?

@lawloretienne μž¬μ‹œλ„ λ§€κ°œλ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜κΈ° 전에 λ‚΄ μ˜ˆμ œμ— μ½”λ“œλ₯Ό μΆ”κ°€ν–ˆλŠ”μ§€ 확인해야 ν•©λ‹ˆλ‹€. ν”ŒλŸ¬κ·ΈμΈμ²˜λŸΌ μž‘λ™ν•˜κΈ° λ•Œλ¬Έμ— μƒˆ 속성은 axios 자체의 μΌλΆ€λ‘œ λ¬Έμ„œν™”λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

config.__retryCount = config.__retryCount || 0;

@KyleRoss ꡬ성 ꡬ성을 전달할 수 μ—†μŠ΅λ‹ˆλ‹€. 각 'config.__reyCount'κ°€ μ •μ˜λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.
https://github.com/axios/axios/blob/v0.19.0/lib/core/mergeConfig.js
이제 μ‚¬μš©μž 지정 속성이 ν•„ν„°λ§λ©λ‹ˆλ‹€.

@dennisreimann μ‚¬μš©μž 지정 ꡬ성은 이제 v0.19μ—μ„œ ν•„ν„°λ§λ˜μ—ˆμœΌλ©° 이제 λ‹€μŒκ³Ό 같이 ꡬ성을 전달할 수 μžˆμŠ΅λ‹ˆλ‹€.

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

@mericsson μž¬μ‹œλ„ν•  λ•Œ μ§€μˆ˜ λ°±μ˜€ν”„κ°€ λ„ˆλ¬΄ ν•„μš”ν•©λ‹ˆλ‹€. λ‚˜λŠ” λ‹€μŒκ³Ό 같이 ν›Œλ₯­ν•˜κ²Œ μž‘λ™ν•©λ‹ˆλ‹€. 이것은 ν˜„μž¬ λͺ¨λ“  였λ₯˜λ₯Ό κ°€λ‘œμ±„κ³  μž¬μ‹œλ„ν•˜κΈ° λ•Œλ¬Έμ— νŠΉμ • 였λ₯˜/μƒνƒœ μ½”λ“œλ₯Ό ν™•μΈν•˜λŠ” 데 μΆ”κ°€ν•˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€.

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

μ‚¬μš©:

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

ꡬ성 μ˜΅μ…˜:
retry - 첫 번째 μ‹€νŒ¨ν•œ μš”μ²­ ν›„ μš”μ²­μ„ μž¬μ‹œλ„ν•˜λŠ” νšŸμˆ˜μž…λ‹ˆλ‹€.
retryDelay - μ‹€νŒ¨ν•œ μš”μ²­ μ‚¬μ΄μ˜ λŒ€κΈ° μ‹œκ°„(λ°€λ¦¬μ΄ˆ)μž…λ‹ˆλ‹€(기본값은 1).

μ–΄λŠ μ‹œμ μ—μ„œ μš”μ μ—μ„œ 이것을 μ’€ 더 ꡬ성 κ°€λŠ₯ν•˜κ²Œ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.

도움에 κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€!

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰