콘텐츠로 이동

4. 외부 API는 실패한다

결제 API를 호출했는데 응답이 늦어 타임아웃이 났다. 결제는 됐는데 우리 DB에 주문이 없다. 사용자가 다시 눌러서 문자가 두 번 나간다. 상태는 꼬이고, 고객은 화가 나 있고, 어디서부터 다시 맞춰야 할지 아무도 모른다.

외부 호출은 성공·실패·모름의 세 가지 결과를 가진다. “모름”(타임아웃, 네트워크 단절)이 가장 위험하며, 이를 설계하지 않은 연동은 미완성이다.

  • 모든 외부 호출에 타임아웃을 명시한다. 기본 무한 대기인 클라이언트가 많다.
  • 재시도는 멱등한 요청에만. 결제처럼 부작용 있는 요청은 멱등 키(idempotency key)를 지원하는지 확인하고, 지원하면 반드시 쓴다.
  • 중복 실행 방지를 DB 제약으로 건다 — 주문번호 UNIQUE, 상태 조건부 UPDATE(진행 중일 때만 완료로) 같은 것. 애플리케이션 코드의 if 검사는 경쟁 조건에서 뚫린다.
  • “모름”으로 끝난 호출의 복구 경로를 정한다: 상대 API의 조회 엔드포인트로 실제 결과를 확인해 상태를 맞추는 재조정(reconcile) 작업.
  • 실패를 빈 값이나 기본값으로 삼키지 않는다. 조용한 실패는 나중에 데이터 불일치로 돌아온다.
  • 모든 외부 호출에 타임아웃이 있다
  • 부작용 있는 호출(결제·발송)에 멱등 키 또는 중복 방지 제약이 있다
  • 중복 방지가 앱 코드가 아니라 DB 제약으로 강제된다
  • 타임아웃으로 끝난 건의 실제 결과를 확인·재조정하는 경로가 있다
  • 실패가 조용히 삼켜지는 catch 블록이 없다