REST API와 네트워크 오류에 대응하는 자바스크립트 재시도 전략

0

자바스크립트를 사용하여 애플리케이션을 개발할 때, REST API와 마이크로서비스는 필수적인 구성 요소입니다. 그러나 때때로 우리는 일시적인 오류, 불안정한 연결, 서비스 중단과 같은 문제에 직면하게 됩니다. 이러한 상황에서 효과적인 재시도 전략이 없다면 애플리케이션이 중단되어 사용자 경험이 크게 저하될 수 있습니다.

재시도 전략은 탄력적인 애플리케이션의 핵심 개념으로, 애플리케이션이 일시적인 오류나 네트워크 결함을 효과적으로 처리할 수 있게 돕습니다. 마치 여행자가 나쁜 날씨나 폐쇄된 도로를 만났을 때 다시 시도할 방법을 찾는 것처럼, 애플리케이션도 갑작스러운 문제를 만났을 때 재시도 전략을 통해 문제를 해결할 수 있습니다.

이 글에서는 자바스크립트를 이용한 재시도 로직 구현 방법을 자세히 설명하고, 실제 사례와 예제를 통해 어떻게 이러한 전략을 효과적으로 적용할 수 있는지 알아보겠습니다. 끝까지 읽어보시면 여러분의 애플리케이션 개발에 큰 도움이 될 것입니다.

1. 고정된 간격 재시도

고정된 간격 재시도 전략은 일정한 시간 간격으로 재시도를 시도하는 방법입니다. 이 전략은 특히 간단하고 이해하기 쉬우며, 일시적인 네트워크 오류나 서버 과부하 상태에서 유용하게 사용할 수 있습니다. 예를 들어, 5초 간격으로 세 번의 재시도를 시도하는 것을 고려해 볼 수 있습니다. 이 방식은 네트워크나 서버에 과도한 부하를 주지 않으면서도 문제를 해결할 수 있는 기회를 제공합니다.

고정된 간격 재시도 전략은 다음과 같은 경우에 특히 유용합니다:

  • 일시적인 네트워크 오류: 일시적인 네트워크 문제나 서비스 중단은 짧은 시간 후에 해결될 수 있습니다. 일정한 간격으로 재시도하면 이러한 문제를 효과적으로 처리할 수 있습니다.
  • 서버 과부하: 서버가 일시적으로 과부하 상태에 있을 때, 일정한 간격으로 재시도하면 서버가 부하를 처리하고 정상 상태로 돌아올 시간을 줍니다.
  • 단순 구현: 이 전략은 간단하고 구현이 용이하여, 초보자나 간단한 애플리케이션에서 쉽게 적용할 수 있습니다.

고정된 간격 재시도의 예제 코드는 다음과 같습니다:

const axios = require("axios");

const fetchDataWithFixedRetry = async (url, retries, interval) => {
  for (let i = 0; i <= retries; i++) {
    try {
      const response = await axios.get(url);
      console.log(`Success: ${response.status}`);
      return response.data;
    } catch (error) {
      if (i < retries) {
        console.log(`Attempt ${i + 1} failed. Retrying in ${interval} ms...`);
        await new Promise((resolve) => setTimeout(resolve, interval));
      } else {
        console.log("All retries failed");
        throw error;
      }
    }
  }
};

const url = "https://sample.api.com/1";
fetchDataWithFixedRetry(url, 3, 5000).catch(console.error);

이 예제는 고정된 간격 재시도 전략을 사용하여 주어진 URL에서 데이터를 가져오려고 시도합니다. 각 시도는 실패 시 5초 후에 다시 시도하며, 최대 3번의 재시도를 시도합니다.

2. 지수적 백오프와 재시도 한계

지수적 백오프와 재시도 한계를 결합한 전략은 지수적 백오프의 장점에 재시도 횟수 제한을 추가한 방식입니다. 이는 무한정 재시도를 방지하고, 일정 횟수 이상의 재시도 후에는 사용자에게 오류를 알리거나 대체 행동을 취할 수 있게 합니다. 예를 들어, 세 번의 재시도 후에도 실패하면 오류 메시지를 표시하거나, 다른 방법으로 데이터를 처리할 수 있습니다.

이 전략은 효율성과 안정성을 동시에 추구하는 방식으로, 대부분의 실무 환경에서 널리 사용됩니다. 특히, 중요한 데이터 전송이나 사용자 인터랙션이 많은 애플리케이션에서 이 전략을 사용하면 신뢰성을 높일 수 있습니다. 지수적 백오프와 재시도 한계의 장점은 다음과 같습니다:

  • 효율적인 재시도: 지수적 백오프는 각 재시도 사이의 대기 시간을 늘림으로써 서버나 네트워크에 과부하를 주지 않으면서도 재시도를 효과적으로 관리할 수 있습니다.
  • 재시도 횟수 제한: 무한정 재시도를 방지하여, 시스템 자원을 낭비하지 않고 효율적으로 사용할 수 있습니다.
  • 사용자 경험 개선: 일정 횟수 이상의 재시도 후에는 사용자에게 명확한 피드백을 제공하여, 사용자가 문제를 인식하고 적절히 대응할 수 있게 합니다.

지수적 백오프와 재시도 한계를 적용한 예제 코드는 다음과 같습니다:

const axios = require("axios");

const fetchDataWithBackoffAndLimit = async (url, retries, delay) => {
  for (let i = 0; i <= retries; i++) {
    try {
      const response = await axios.get(url);
      console.log(`Success: ${response.status}`);
      return response.data;
    } catch (error) {
      if (i < retries) {
        const backoff = delay * Math.pow(2, i);
        console.log(`Attempt ${i + 1} failed. Retrying in ${backoff} ms...`);
        await new Promise((resolve) => setTimeout(resolve, backoff));
      } else {
        console.log("All retries failed");
        throw error;
      }
    }
  }
};

const url = "https://sample.api.com/1";
fetchDataWithBackoffAndLimit(url, 3, 1000).catch(console.error);

이 코드는 지수적 백오프와 재시도 한계를 결합한 전략을 사용하여 주어진 URL에서 데이터를 가져오려고 시도합니다. 각 시도는 실패 시 지수적으로 증가하는 대기 시간 후에 다시 시도하며, 최대 3번의 재시도를 시도합니다.

3. 선형 백오프

선형 백오프는 일정한 간격으로 한 걸음씩 앞으로 나아가는 것처럼 올곧은 길을 걷는 것과 같습니다. 재시도할 때마다, 조금 더 기다리지만 대기 시간은 매번 같은 양만큼 늘어납니다. 꾸준하게 예측 가능하기 때문에 서두르거나 비틀거리지 않도록 합니다.

선형 백오프 전략은 다음과 같은 경우에 특히 유용합니다:

  • 예측 가능성: 일정한 간격으로 대기 시간을 늘리기 때문에 재시도 간격을 예측하기 쉽습니다. 이는 시스템이 복구할 시간을 제공하면서도 일관된 성능을 유지할 수 있게 합니다.
  • 단순성: 구현이 간단하고, 매번 동일한 양의 대기 시간을 추가하기 때문에 복잡한 계산이 필요하지 않습니다.
  • 안정성: 네트워크나 서버의 상태를 안정적으로 모니터링하면서 적절한 재시도 간격을 유지할 수 있습니다.

선형 백오프의 장점은 예측 가능성과 안정성에 있으며, 이를 통해 네트워크나 서버에 과도한 부하를 주지 않으면서도 재시도를 효과적으로 관리할 수 있습니다.

선형 백오프 전략의 예제 코드는 다음과 같습니다:

const axios = require("axios");

let attemptCounter = 0; // 실패 시뮬레이션 시도 횟수 추적

/**
 * 이 함수는 HTTP 요청에 대해 axios를 사용하는 선형 백오프 전략을 보여줍니다.
 * 초기 시도에서 네트워크 실패를 시뮬레이션한 다음 성공하여, 애플리케이션이 적절한 재시도 로직을 기반으로 일시적인 문제로부터 어떻게 회복할 수 있는지 보여줍니다.
 *
 * 선형 백오프 전략은 재시도 간의 지연 시간을 고정적으로 증가시켜 재시도 간격을 관리하는 균형 잡힌 접근 방식을 제공하며, 다음 시도 전에 시스템이 복구할 수 있는 시간을 제공합니다.
 *
 * 매개변수:
 * - url: 데이터를 가져올 URL
 * - retries: 재시도 허용 횟수
 * - delay: 첫 번째 재시도 전 초기 지연 시간
 * - increment: 재시도 후 지연 시간 증가량
 *
 * 실패 시, 이 함수는 지정된 지연 시간을 기다린 후 선형 백오프 계산을 기반으로 증가한 지연 시간으로 요청을 재시도 합니다.
 */
const fetchDataWithLinearBackoff = async (url, retries, delay, increment) => {
  try {
    attemptCounter++;
    if (attemptCounter <= 3) {
      throw new Error("Simulated network failure");
    }

    const response = await axios.get(url);
    console.log(`Success: ${response.status}`);
    return response.data;
  } catch (error) {
    console.log(
      `Attempt ${attemptCounter} failed with error: ${error.message}. Waiting ${delay} ms before retrying.`
    );
    if (retries > 0) {
      await new Promise((resolve) => setTimeout(resolve, delay));
      return fetchDataWithLinearBackoff(
        url,
        retries - 1,
        delay + increment,
        increment
      );
    } else {
      throw new Error("All retries failed");
    }
  }
};

const url = "https://sample.api.com/1";
fetchDataWithLinearBackoff(url, 5, 1000, 2000).catch(console.error);

/**
 * 결과물:
 * 시도 1 실패 오류: 시뮬레이션한 네트워크 실패. 재시도 전 1000 밀리초를 기다립니다.
 * 시도 2 실패 오류: 시뮬레이션한 네트워크 실패. 재시도 전 3000 밀리초를 기다립니다.
 * 시도 3 실패 오류: 시뮬레이션한 네트워크 실패. 재시도 전 5000 밀리초를 기다립니다.
 * 성공: 200
 */

이 코드는 선형 백오프 전략을 사용하여 주어진 URL에서 데이터를 가져오려고 시도합니다. 각 시도는 실패 시 일정한 양만큼 증가한 대기 시간 후에 다시 시도하며, 최대 5번의 재시도를 시도합니다.

4. 고정 지연

고정 지연 전략은 재시도 간의 대기 시간을 일정하게 유지하는 방식입니다. 얼마나 멀리 달렸는지에 관계없이 일정한 간격으로 숨을 쉬기 위해 멈추는 것을 상상해 보세요. 이 전략은 애플리케이션이 너무 빨리 지치지 않도록 보장하고 일관된 리듬을 제공합니다. 시도 횟수와 상관없이 재시도 간 대기 시간을 일정하게 유지함으로써 안정성을 제공합니다.

고정 지연 전략은 다음과 같은 경우에 유용합니다:

  • 일관된 간격: 모든 재시도 사이의 대기 시간이 동일하기 때문에 예측 가능성이 높습니다.
  • 간단한 구현: 복잡한 로직 없이 고정된 시간만큼 대기한 후 재시도하면 되므로 구현이 간단합니다.
  • 안정적 성능: 일정한 대기 시간으로 인해 시스템이 과부하 되지 않고 안정적인 성능을 유지할 수 있습니다.

다음은 고정 지연 전략의 예제 코드입니다:

const axios = require("axios");

let attemptCounter = 0; // 시나리오 시뮬레이션을 위한 시도 횟수 추적 방법

/**
 * axios를 사용하여 HTTP 요청에 대한 고정 지연 재시도 전략을 구현하는 방법을 시도합니다.
 * 초기 시도에 대한 실패를 시뮬레이션하여 고정 지연 재시도가 시도 횟수에 상관없이 재시도 전에 미리 계산된 시간을 대기함으로써 일시적인 오류를 효과적으로 관리할 방법을 설명합니다.
 *
 * 고정 지연 방식은 재시도 간격을 일정하게 유지하여 시스템 복구 및 오류 해결을 다음 시도 전에 가능하게 하는 간단하고 예측 가능한 방법을 제공합니다. 이 전략은 복구 예상 시간이 일정한 상황에서 특히 유용합니다.
 *
 * 매개변수:
 * - url: HTTP GET 요청을 위한 엔드포인트 URL
 * - retries: 종료 전 재시도 횟수
 * - delay: 재시도 전 대기하는 고정 시간(밀리초)
 */
const fetchData = async (url, retries, delay) => {
  try {
    attemptCounter++;

    if (attemptCounter <= 3) {
      throw new Error("Simulated network failure");
    }

    const response = await axios.get(url);
    console.log(`Success: ${response.status}`);
    return response.data;
  } catch (error) {
    console.log(
      `Attempt ${attemptCounter} failed with error: ${error.message}. Waiting ${delay} ms before retrying.`
    );
    if (retries > 0) {
      await new Promise((resolve) => setTimeout(resolve, delay));
      return fetchData(url, retries - 1, delay);
    } else {
      throw new Error("All retries failed");
    }
  }
};

const url = "https://sample.api.com/1";
fetchData(url, 4, 1000).catch(console.error);

/**
 * 결과물:
 * 시도 1 실패 오류: 시뮬레이션한 네트워크 실패. 재시도 전 1000 밀리초를 기다립니다.
 * 시도 2 실패 오류: 시뮬레이션한 네트워크 실패. 재시도 전 1000 밀리초를 기다립니다.
 * 시도 3 실패 오류: 시뮬레이션한 네트워크 실패. 재시도 전 1000 밀리초를 기다립니다.
 * 성공: 200
 */

5. 피보나치 백오프

피보나치 백오프 접근법은 자연의 나선형에서 영감을 얻어 피보나치 수열을 따라 대기 시간을 증가시킵니다. 각 단계는 마지막 두 단계의 지혜를 결합하여, 서두르거나 너무 오래 기다리는 것 사이의 조화로운 균형을 찾아내며, 자연스러운 우아함으로 문제를 헤쳐 나가도록 안내합니다.

피보나치 백오프는 다음과 같은 경우에 유용합니다:

  • 균형 잡힌 지연 시간: 피보나치 수열을 사용하여 대기 시간을 증가시킴으로써 급격한 지연과 완화된 지연 사이의 균형을 유지합니다.
  • 자연스러운 증분: 피보나치 수열의 자연스러운 증분을 활용하여, 시스템이 과부하 되지 않으면서도 재시도를 효과적으로 관리할 수 있습니다.
  • 안정적 성능: 일정한 규칙을 따르기 때문에 재시도 간의 지연 시간을 예측할 수 있으며, 이를 통해 시스템의 안정성을 높일 수 있습니다.

다음은 피보나치 백오프 전략의 예제 코드입니다:

const axios = require("axios");

let attemptCounter = 0; // 시뮬레이션을 위한 현재 시도 추적

/**
 * 주어진 인덱스에 대한 피보나치 수를 계산합니다. 피보나치 수열은 보통 0과 1의 시작으로 각각의 수가 앞의 두 수의 합이 되는 수열입니다.
 *
 * - index: 피보나치 수열의 위치
 */
const calculateFibonacciNumber = (index) => {
  if (index <= 1) return index;
  let previous = 0,
    current = 1,
    temp;
  for (let i = 2; i <= index; i++) {
    temp = previous + current;
    previous = current;
    current = temp;
  }
  return current;
};

/**
 * axios를 사용하여 HTTP GET 요청에 대한 피보나치 백오프 전략을 기반한 재시도를 수행합니다.
 * 처음 몇 번의 시도에서 네트워크 실패를 시뮬레이션하여, 피보나치 수열을 기반한 지연 시간이 증가하는 재시도 전략을 사용함으로써 애플리케이션이 어떻게 다시 정상 작동하게 되는지 보여줍니다.
 * - url: 요청 보낼 URL
 * - retries: 실패 전 허용된 재시도 횟수
 * - baseDelay: 피보나치 백오프 계산을 위한 기본 지연 시간(밀리초)
 */
const fetchData = async (url, retries, baseDelay) => {
  try {
    attemptCounter++;

    if (attemptCounter <= 2) {
      throw new Error("Simulated network failure");
    }

    const response = await axios.get(url);
    console.log(`Success: ${response.status}`);
    return response.data;
  } catch (error) {
    console.log(
      `Attempt ${attemptCounter} failed with error: ${error.message}. Waiting for the next attempt.`
    );
    if (retries > 0) {
      const delay = calculateFibonacciNumber(5 - retries + 1) * baseDelay;
      console.log(`Waiting ${delay} ms before retrying.`);
      await new Promise((resolve) => setTimeout(resolve, delay));
      return fetchData(url, retries - 1, baseDelay);
    } else {
      throw new Error(
        "All retries failed after " + attemptCounter + " attempts"
      );
    }
  }
};

const url = "https://sample.api.com/1";
fetchData(url, 5, 100).catch(console.error);

/**
 * 결과물:
 * 시도 1 실패 오류: 시뮬레이션한 네트워크 실패. 재시도 전 100 밀리초를 기다립니다.
 * 시도 2 실패 오류: 시뮬레이션한 네트워크 실패. 재시도 전 200 밀리초를 기다립니다.
 * 시도 3 실패 오류: 시뮬레이션한 네트워크 실패. 재시도 전 300 밀리초를 기다립니다.
 * 시도 4 실패 오류: 시뮬레이션한 네트워크 실패. 재시도 전 500 밀리초를 기다립니다.
 * 성공: 200
 */

이 코드는 피보나치 백오프 전략을 사용하여 주어진 URL에서 데이터를 가져오려고 시도합니다. 각 시도는 실패 시 피보나치 수열을 기반으로 증가하는 대기 시간 후에 다시 시도하며, 최대 5번의 재시도를 시도합니다.

6. 무작위 재시도

무작위 재시도 전략은 주사위를 굴려 대기 시간을 결정하는 것처럼, 재시도 타이밍에 우연한 요소를 도입합니다. 이런 무작위성은 시도를 보다 골고루 분산시켜, 모두가 한꺼번에 통과하려는 부담을 줄이면서 시스템에 대한 부담을 감소시킵니다. 시도를 분산하고 시스템 부하를 줄이기 위해 재시도 전임의 대기 시간을 무작위로 선택합니다.

무작위 재시도 전략의 주요 이점은 다음과 같습니다:

  • 부하 분산: 동일한 시간에 많은 요청이 집중되는 것을 방지하여 시스템 부하를 줄입니다.
  • 충돌 방지: 여러 클라이언트가 동시에 동일한 서버에 요청을 보내는 것을 피할 수 있습니다.
  • 적응성: 네트워크나 서버 상태에 따라 유연하게 대처할 수 있습니다.

다음은 무작위 재시도 전략의 예제 코드입니다:

const axios = require("axios");

let attemptCounter = 0; // 시도 횟수 추적 및 네트워크 오류 시뮬레이션.

/**
 * 무작위 지연을 포함한 재시도와 함께 axios를 사용하여 HTTP GET 요청을 수행합니다.
 * 네트워크 오류 시뮬레이션 전략은 특정 최소 범위와 최대 범위 사이의 임의 지연을 재시도하여 복구할 방법을 설명합니다.
 * 재시도 간격의 랜덤화는 부하 분산과 시스템 피크 압력 감소에 도움이 됩니다.
 *
 * - url: HTTP GET 요청을 위한 엔드포인트 URL
 * - retries: 종료 전 재시도 횟수
 * - minDelay: 재시도 전 최소 지연 시간(밀리초)
 * - maxDelay: 재시도 전 최대 지연 시간(밀리초)
 */
const fetchData = async (url, retries, minDelay, maxDelay) => {
  try {
    attemptCounter++;

    if (attemptCounter <= 2) {
      throw new Error("Simulated network failure");
    }

    const response = await axios.get(url);
    console.log(`Success: ${response.status}`);
    return response.data;
  } catch (error) {
    console.log(
      `Attempt ${attemptCounter} failed with error: ${error.message}.`
    );
    if (retries > 0) {
      const randomDelay = Math.random() * (maxDelay - minDelay) + minDelay; // 임의 지연 시간 계산
      console.log(`Waiting ${Math.round(randomDelay)} ms before retrying.`);
      await new Promise((resolve) =>
        setTimeout(resolve, Math.round(randomDelay))
      );
      return fetchData(url, retries - 1, minDelay, maxDelay);
    } else {
      throw new Error(`All retries failed after ${attemptCounter} attempts`);
    }
  }
};

const url = "https://sample.api.com/1";
fetchData(url, 3, 500, 1500).catch(console.error);

/**
 * 결과물:
 * 시도 1 실패 오류: 시뮬레이션한 네트워크 실패. 재시도 전 1487 밀리초를 기다립니다.
 * 시도 2 실패 오류: 시뮬레이션한 네트워크 실패. 재시도 전 777 밀리초를 기다립니다.
 * 성공: 200
 */

이 코드는 무작위 재시도 전략을 사용하여 주어진 URL에서 데이터를 가져오려고 시도합니다. 각 시도는 실패 시 무작위로 선택된 대기 시간 후에 다시 시도하며, 최대 3번의 재시도를 시도합니다.

무작위 재시도 전략의 주요 장점은 다음과 같습니다:

7. 즉시 재시도

  • 부하 분산: 동일한 시간에 많은 요청이 집중되는 것을 방지하여 시스템 부하를 줄입니다.
  • 충돌 방지: 여러 클라이언트가 동시에 동일한 서버에 요청을 보내는 것을 피할 수 있습니다.
  • 적응성: 네트워크나 서버 상태에 따라 유연하게 대처할 수 있습니다.
  • 때로는 가장 좋은 접근 방식은 즉시 다시 시도하는 것입니다. 특히 빠르게 문제가 해결될 것 같을 때 더욱 좋습니다. 이 전략은 기회를 잡는 것으로, 문제의 첫 징후가 나타나는 즉시 다시 시작할 준비를 하는 것입니다. 지체 없이 즉시 재시도하므로, 신속하게 해결할 수 있는 문제에 이상적입니다.
  • 즉시 재시도 전략의 주요 이점은 다음과 같습니다:
  • #UL type=number
  • 빠른 문제 해결: 지체 없이 즉시 재시도함으로써 일시적인 오류를 빠르게 해결할 수 있습니다.
  • 간단한 구현: 복잡한 대기 시간 계산 없이 즉시 재시도하므로 구현이 간단합니다.
  • 효율성: 즉각적인 재시도를 통해 성공 가능성을 높이며, 빠르게 문제가 해결될 가능성이 높은 상황에서 특히 유용합니다.

즉시 재시도 전략의 예제 코드는 다음과 같습니다:

const axios = require("axios");

let attemptCounter = 0; // 네트워크 실패를 시뮬레이션하기 위해 현재 시도 횟수 추적.

/**
 * 실패 시 즉각적인 재시도 전략을 사용하여 axios를 사용한 HTTP GET 요청을 실행합니다.
 * 이 접근법은 초반에 몇 번의 시도를 통해 네트워크 실패를 시뮬레이션하여, 빠르게 해결할 수 있는 일시적인 문제를 어떻게 애플리케이션이 지연 없이 즉시 재시도하여 적용되는지 설명합니다.
 *
 * 즉각적인 재시도는 오류가 일시적일 가능성이 높고 지연을 적용하지 않고 해결될 수 있는 상황에서 사용됩니다. 이는 네트워크 안정성이 변동하는 환경에서 성공적인 요청 가능성에서 효과적입니다.
 *
 * - url: HTTP GET 요청을 위한 엔드포인트 URL
 * - retries: 종료 전 재시도 횟수
 */
const fetchData = async (url, retries) => {
  try {
    attemptCounter++;

    if (attemptCounter <= 3) {
      throw new Error("Simulated network failure");
    }

    const response = await axios.get(url);
    console.log(`Success: ${response.status}`);
    return response.data;
  } catch (error) {
    console.log(
      `Attempt ${attemptCounter} failed with error: ${error.message}.`
    );
    if (retries > 0) {
      console.log("Retrying immediately.");
      return fetchData(url, retries - 1);
    } else {
      throw new Error(`All retries failed after ${attemptCounter} attempts`);
    }
  }
};

const url = "https://sample.api.com/1";
fetchData(url, 5).catch(console.error);

/**
 * 결과물:
 * 시도 1 실패 오류: 시뮬레이션한 네트워크 실패. 즉시 재시도.
 * 시도 2 실패 오류: 시뮬레이션한 네트워크 실패. 즉시 재시도.
 * 시도 3 실패 오류: 시뮬레이션한 네트워크 실패. 즉시 재시도.
 * 성공: 200
 */

이 코드는 즉시 재시도 전략을 사용하여 주어진 URL에서 데이터를 가져오려고 시도합니다. 각 시도는 실패 시 지체 없이 즉시 재시도하며, 최대 5번의 재시도를 시도합니다. 이 전략은 일시적인 오류를 빠르게 해결하는 데 효과적입니다.

재시도 로직을 위한 npm 패키지 활용

효과적인 재시도 로직을 구현하기 위해 npm 패키지를 활용하는 것은 매우 유용합니다. 이를 통해 재시도 로직을 간단하고 효율적으로 설정할 수 있습니다. 여기서는 대표적인 두 가지 npm 패키지, axios-retryretry를 활용하는 방법을 알아보겠습니다.

axios-retry

axios-retry는 axios 요청에 재시도 기능을 추가하는 간단한 방법을 제공합니다. 이 라이브러리는 네트워크 오류 또는 특정 HTTP 응답 코드와 같은 특정 조건에서 실패한 요청을 자동으로 재시도할 수 있고, 지수 백오프를 포함한 구성 가능한 재시도 전략을 지원합니다.

먼저 axios-retry를 사용하려면 axios와 axios-retry를 설치해야 합니다.

npm install axios axios-retry

or

yarn add axios axios-retry

설치 후, 다음과 같이 axios-retry를 구성할 수 있습니다:

import axios from "axios";
import axiosRetry from "axios-retry";

// 자동 재시도 요청을 위한 axios-retry 구성
axiosRetry(axios, {
  retries: 3, // 재시도 횟수
  retryDelay: axiosRetry.exponentialDelay, // 재시도 사이에 지수 백오프 지연 사용
});

// 실패 시 재시도되는 axios 요청
axios
  .get("https://sample.api.com/1")
  .then((response) => console.log(response.data))
  .catch((error) => console.error(error));

프런트엔드에서 axios-retry를 사용하면 애플리케이션에서 HTTP 요청에 대한 재시도 처리를 크게 간소화하여 최소한의 코드 추가로 견고하고 믿을 수 있는 웹 앱을 만들 수 있습니다.

retry

retry 패키지는 코드에 재시도 기능을 추가한 유연한 방법을 제공하고, 실패 시 여러 번 시도하려는 비동기 연산이나 로직 처리에 적합합니다. 이제 사용 방법에 대한 기본 가이드를 보시죠.

먼저, npm 또는 yarn을 사용해서 패키지를 설치하세요.

npm install retry

or

yarn add retry

아래 예제는 실패할 수 있는 작업을 수행하기 위해 retry를 사용하는 간단한 예시입니다:

const retry = require("retry");
const axios = require("axios"); // axios가 HTTP 요청에 사용된다고 가정해봅시다.

async function fetchData(url) {
  const operation = retry.operation({
    retries: 3, // 최대 재시도 횟수
    factor: 2, // 지연에 대한 지수 계수
    minTimeout: 1000, // 첫 번째 재시도를 시작하기 전의 시간(밀리초)
    maxTimeout: 2000, // 두 번째 재시도 사이의 최대 시간(밀리초)
  });

  operation.attempt(async (currentAttempt) => {
    try {
      const response = await axios.get(url);
      console.log("Data:", response.data);
    } catch (error) {
      console.log(`Attempt ${currentAttempt} failed: ${error.message}`);
      if (operation.retry(error)) {
        console.log(`Retrying...`);
        return;
      }
      console.error("Request failed after retries:", error.message);
    }
  });
}

fetchData("https://sample.api.com/1");

retry 패키지는 강력하고 유연합니다. 단지 HTTP 요청을 넘어서 넓은 범위의 재시도 상황을 만드는 데 적합합니다. 데이터베이스 작업, 파일 시스템 접근 또는 실패 시 재시도가 필요한 다른 작업과 같은 다양한 비동기 작업에 알맞은 재시도 로직을 적용할 수 있습니다.

마치며

재시도 로직은 현대의 자바스크립트 애플리케이션에서 안정성과 복원력을 보장하는 핵심적인 요소입니다. 네트워크 오류나 일시적인 문제는 불가피하지만, 이를 효과적으로 관리하고 처리하는 능력은 애플리케이션의 품질을 크게 향상시킵니다.

첫째, 재시도 로직의 구현은 신중한 시기 결정이 필요합니다. 모든 오류에 대해 무조건적인 재시도를 시도하는 것은 비효율적일 뿐만 아니라, 시스템 자원을 낭비할 수 있습니다. 따라서 오류가 일시적인지, 후속 시도를 통해 해결될 가능성이 있는지 면밀히 분석한 후 재시도를 결정해야 합니다.

둘째, 재시도 횟수의 제한은 필수적입니다. 무한 루프에 빠지지 않도록 최대 재시도 횟수를 설정함으로써 시스템이 불필요하게 과부하되지 않도록 해야 합니다. 이는 자원 낭비를 방지하고, 애플리케이션의 성능을 유지하는 데 중요합니다.

셋째, 사용자 경험을 최우선으로 고려해야 합니다. 클라이언트 애플리케이션에서는 재시도 로직이 사용자 경험을 저해하지 않도록 설계해야 합니다. 긴 지연 시간이나 빈번한 재시도는 사용자의 불편을 초래할 수 있으므로, 사용자에게 적절한 피드백을 제공하고, 필요한 경우 대안 경로를 제공해야 합니다.

마지막으로, 재시도 로직은 직접 구현하거나 기존의 npm 패키지를 활용할 수 있습니다. axios-retry와 retry와 같은 패키지는 재시도 로직을 간단하고 효율적으로 적용할 수 있는 도구를 제공합니다. 이러한 도구를 활용하면 최소한의 코드 수정으로 견고하고 신뢰할 수 있는 애플리케이션을 구축할 수 있습니다.

재시도 로직의 궁극적인 목표는 애플리케이션의 견고함과 사용자 만족도를 향상시키는 것입니다. 안정적이고 복원력 있는 시스템을 구축함으로써, 사용자는 애플리케이션을 신뢰하고, 개발자는 안정적인 서비스를 제공할 수 있게 됩니다. 이러한 전략을 통해 일시적인 오류를 우아하게 처리할 수 있는 능력은 경쟁력 있는 애플리케이션 개발의 중요한 요소입니다.

재시도 로직을 통해 여러분의 애플리케이션이 더욱 견고하고 신뢰할 수 있는 시스템으로 발전하기를 바라며, 이 과정에서 발생할 수 있는 도전과제들을 극복하고, 사용자에게 최상의 경험을 제공하는 애플리케이션을 구축하시길 기원합니다.

참고 자료: Anurag Gupta, “Implement Retry logic using JavaScript”

Leave a Reply