Engineering Stories

Engineering Story

무음 실패한 월정산을 다음 운영 주기까지 닫은 장애 대응

복구와 재발 방지에서 멈추지 않고 다음 월정산의 저장·후속 배치·조회 반영까지 확인한 사례

  • PostgreSQL
  • Batch
  • SQS
  • Observability

왜 바꿔야 했는가

월정산 중 일부 수수료 데이터의 오류가 전체 작업을 롤백시켜 정산 결과가 생성되지 않았습니다. 후속 배치는 대상이 0건이어도 성공처럼 끝나 운영자가 앞 단계의 실패를 바로 알기 어려웠고, 복구 도구와 데이터 동기화에도 별도의 오류가 있어 대규모 정정과 재처리가 필요했습니다.

제가 처음 설계한 정산 시스템은 아니었습니다. 이 사례에서 필요한 역할은 흩어진 현상과 후속 과제를 하나의 원인으로 뭉뚱그리지 않고, 무엇을 먼저 복구하고 어떤 방어 장치를 어느 순서로 적용할지 관계자와 맞춘 뒤 실제 운영 결과까지 닫는 일이었습니다.

무엇을 확인했는가

기획·운영 담당자와 이슈별 진행 상태와 기대 동작을 맞추고, 장애를 계산·저장·후속 실행·복구·운영 확인 단계로 나눴습니다.

  • 수수료를 비율로 나누는 과정에서 음수가 발생할 수 있었고 한 건의 오류가 전체 정산을 롤백시켰습니다.
  • 앞 단계 결과가 없을 때 후속 작업은 대상 0건으로 끝났지만 별도 경고가 없었습니다.
  • 재실행 과정의 기간 계산과 일부 동기화 흐름이 잘못된 데이터를 남길 수 있었습니다.
  • 무료 지급 사유와 자료 사용 로그처럼 이후 운영 판단에 필요한 정보도 충분히 남지 않았습니다.

장애 원인, 이미 오염된 데이터의 복구와 앞으로의 재발 방지를 분리해야 순서를 잃지 않고 진행할 수 있었습니다.

어떤 선택을 했는가

수수료 분배는 음수가 구조적으로 발생하지 않는 cascade 방식으로 바꾸고, 오류 한 건이 전체 결과를 지우지 않도록 사전 검증과 부분 저장을 적용했습니다. 대상이 0건이면 Slack으로 알리고, 선행 월정산 결과가 없으면 후속 실행을 막는 가드를 추가했습니다.

재실행은 영향 범위를 먼저 확인한 뒤 안전하게 적용할 수 있는 도구로 정리했습니다. 데이터 동기화 실패에는 알림과 자가 보정 경로를 추가했고, 무료 지급 사유와 자료 단위 사용 로그도 운영자가 확인할 수 있게 보완했습니다.

어떻게 전환하고 검증했는가

이슈 구조화와 기술 분석부터 구현, production 배포, 백필과 재처리 검증까지 직접 진행했습니다. 정산 기획 담당자에게 변수명과 원하는 처리 규칙을 확인하고, 각 이슈의 조치·배포·검증 상태를 한 문서에서 계속 갱신해 관계자들이 같은 순서로 판단하도록 했습니다.

복구와 방어 장치 배포 뒤에는 다음 월정산 전에 위험 요소를 다시 점검했습니다. 실제 실행 후 Slack 성공 건수와 DB 저장 결과, 후속 정산, 조회 화면 반영과 신규 오류 여부를 사후 확인했습니다. 정상 실행에서 관측할 수 없는 실패 전용 가드까지 작동했다고 확대하지 않고, 실제로 확인한 경로만 결과로 남겼습니다.

이후 무엇이 달라졌는가

오염 데이터를 정정·재처리해 장애가 난 월정산을 마감했고, 수수료 산식, 부분 저장, 알림, 실행 가드와 안전한 재실행 체계를 production에 적용했습니다. 다음 월정산은 저장 결과와 알림 건수가 일치했고 후속 배치와 조회 반영에서도 누락이나 신규 오류 없이 정상 마감했습니다.

이번 경험의 성과는 장애를 한 번 복구한 데서 끝나지 않습니다. 서로 다른 원인과 후속 과제를 구조화하고 관계자와 해결 순서를 맞춘 뒤, 다음 운영 주기에서 재발 징후가 없는지 확인할 때까지 작업을 종결한 데 있습니다.

다시 한다면

정산 실행 전 입력 데이터의 불변 조건과 단계별 대상 건수를 자동 점검하고, 각 단계의 결과가 다음 단계의 실행 조건으로 명시되도록 설계하겠습니다. 재처리 도구도 평시부터 dry-run, 영향 범위와 검증 쿼리를 같은 흐름으로 제공하겠습니다.

처음 만든 시스템이 아니더라도 장애를 단계별로 분해하고, 기술 수정과 운영 절차를 함께 맞추며, 다음 주기까지 결과를 관찰하는 원칙은 유지할 것입니다.