안녕하세요, 올리브영에서 주문·배송 도메인의 백엔드 개발을 담당하고 있는 데이먼입니다. 오늘은 '배송준비중'이라는 이유로 막혀 있던 주문 취소를, 고객이 앱에서 직접 할 수 있게 바꾼 이야기를 해 보려 합니다.
밤 11시, 한 고객이 결제를 마치고 3분 뒤에야 립스틱을 원하던 것과 다른 색상으로 골랐다는 것을 알아챕니다. 영양제를 사려던 것과 다른 용량으로 담았을 수도 있습니다. 주문을 취소하려고 앱을 다시 열었는데 취소 버튼이 없습니다. 배송 조회를 눌러 봐도 송장 번호가 없고 상품은 아직 어디에도 가 있지 않은데, 상태는 '배송준비중'입니다.
🙋 고객: "제가 주문한 상품이 아직 출발도 안 했는데, 왜 취소가 안 되죠?"
올리브영 고객센터로 꾸준히 들어오던 질문입니다. 저희는 이 질문에 답하려고 취소 가능 시점을 실물 출고 직전까지 늦췄고, 작업은 조건문 수정에서 시작해 이벤트 파이프라인과 분산 락, 장애 격리까지 이어졌습니다.
취소 버튼은 왜 그렇게 일찍 사라질까
'배송 준비 중 취소 불가'는 인색한 정책이라기보다 안전장치에 가깝습니다. 물류가 이미 움직인 뒤에 취소가 성립하면 상품은 고객에게 가고 결제만 취소됩니다. 되돌릴 방법이 마땅치 않습니다. 그래서 대부분의 커머스는 취소 문을 실제 한계선보다 넉넉히 앞당겨 닫습니다.
국내만의 사정은 아닙니다. Amazon은 아직 발송되지 않은 주문에도 '취소'가 아니라 취소 요청(Request cancellation)을 받고, 요청이 받아들여지지 않을 수 있다고 안내합니다. 실패하면 수령 거부나 반품 절차로 넘어갑니다. eBay는 한 단계 더 나아가, 구매자의 취소 요청을 판매자가 3일 안에 수락하거나 거절하고 응답이 없으면 자동으로 거절합니다. 두 방식 모두 취소를 그 자리에서 확정하지 않고 결과를 나중에 통보하는 비동기 모델입니다. 물류 진행을 확실히 멈출 수 없다면 고객에게 확답을 주지 않는 편이 안전하다는 판단입니다.
저희는 반대쪽을 택했습니다. 고객이 버튼을 누른 그 순간에 취소를 확정하고, 뒤처리는 시스템이 책임지는 구조입니다. 이 선택 하나가 이후의 설계를 대부분 결정했습니다. 아래에서 다룰 분산 락과 장애 격리는 전부 "즉시 확정"을 약속한 대가로 떠안은 일입니다.
사실 센터배송의 기존 취소 마감은 물류센터의 출하 지시(작업 할당) 시점이었습니다. 문제는 할당이 생각보다 이른 단계라는 점이었습니다. 할당은 "이 주문을 어느 설비에서 처리하겠다"는 예약에 가깝습니다. 그 시점에 상품은 여전히 선반 위에 있고, 실제 출고까지 몇 시간이 남기도 합니다. 재고는 아직 센터 안에 있는데 시스템은 이미 취소를 막은 상태였고, 그 간극은 고스란히 고객 몫이었습니다.
제도적으로도 짚어 볼 부분이 있었습니다. 전자상거래법의 청약철회권과 이용약관 관점에서 보면, 상품이 아직 물류센터를 떠나지 않았다면 취소할 수 있어야 한다는 것이 자연스러운 해석이었습니다. 그래서 목표를 이렇게 잡았습니다. "취소 마감 시점을 '물류가 움직이기 시작한 시점'이 아니라 '되돌릴 수 없게 된 시점'으로 옮기자."
💡 참고: 「전자상거래 등에서의 소비자보호에 관한 법률」 제17조 제1항은 소비자가 계약 내용에 관한 서면을 받은 날(재화 공급이 그보다 늦으면 재화를 공급받거나 공급이 시작된 날)부터 7일 이내에 청약을 철회할 수 있다고 정합니다. 올리브영 이용약관(v4.1, 2026년 8월 20일 시행) 제23조 제2항도 "회원은 구매한 상품 등이 발송되기 전까지 취소 요청을 할 수 있으며, 배송 중인 경우에는 취소 요청이 아닌 반품 절차에 따라 처리"된다고 규정합니다.
되돌릴 수 없는 순간은 언제인가
그 순간을 정의하는 것이 첫 관문이었습니다. 기준은 다음과 같이 두 가지로 잡았습니다. 이 두 기준을 센터배송(물류센터 배송), 업체배송(파트너 브랜드사가 직접 배송), 오늘드림(매장에서 출발하는 당일배송) 세 배송유형에 적용해 보니 답이 제각각이었습니다. 세 유형에 같은 시점을 쓰는 대신, 각각 가장 늦게까지 미룰 수 있는 지점을 따로 찾기로 했습니다.
취소 마감 판단 기준
1. 물리적으로 되돌릴 수 없는가: 피킹(집품)이 끝나 상품이 선반을 떠났는가
2. 외부에 되돌릴 수 없는 요청이 나갔는가: 송장이 발행됐는가, 라이더가 배차됐는가| 배송유형 | 기존 취소 마감 시점 | 개선 후 취소 마감 시점 |
|---|---|---|
| 센터배송 | 출하 지시(작업 할당) | 피킹 완료: 상품이 실제로 선반을 떠난 뒤 |
| 업체배송 | 출하 지시 | 송장 등록: 택배사에 인계가 확정된 뒤 |
| 오늘드림 | 주문 접수 확정 | 배차: 라이더가 배정된 뒤 |
아래와 같이 센터배송을 예시로 삼아 주문 흐름을 단계별로 펼쳐 보면, 3단계 출하 지시(작업 할당)와 4단계 피킹 진행이 그동안 취소가 닫혀 있던 구간입니다. 3단계에서는 주문을 처리할 설비가 정해졌을 뿐 상품은 여전히 선반 위에 있고, 4단계도 피킹이 끝나기 전이라 되돌릴 수 있는 단계입니다. 그런데도 기존에는 3단계에 들어서는 순간 취소를 막았습니다. 이번 개선에서는 취소 마감 시점을 상품이 실제로 선반을 떠나는 5단계 피킹 완료로 옮겨, 이 두 단계를 고객에게 다시 열었습니다. 아래 이미지에서 '되찾은 취소 골든타임'으로 표시한 구간이 바로 이 두 단계입니다.
판단 기준을 한곳으로 모으다
시점을 정했으니 이제 코드를 바꿀 차례였는데, 고칠 곳이 한 군데로 모여 있지 않았습니다. 주문서, 마이페이지, 백오피스, 미픽업 정리 배치의 네 곳이 각자 다른 조건으로 취소 가능 여부를 판단하고 있었습니다. 배송유형이 늘어날 때마다 분기가 하나씩 붙어 온 결과였습니다. 하나라도 놓치면 화면에는 버튼이 보이는데 눌러도 실패하는, 가장 피하고 싶은 상황이 만들어집니다. 그래서 조건을 하나씩 손보는 대신 판단 자체를 한곳으로 모았습니다. 주문 배송 정보에 '취소 불가 일시'라는 시점 값 하나를 두고, 규칙을 다음과 같이 단순화했습니다.
- 값이 비어 있으면 → 취소 가능
- 값이 채워져 있으면 → 취소 불가
배송유형별로 다른 것은 값을 채우는 시점뿐입니다. 센터배송은 피킹 완료, 업체배송은 송장 등록, 오늘드림은 배차 시점에 값을 채웁니다. 주문서, 마이페이지, 백오피스, 미픽업 정리 배치는 배송유형과 관계없이 이 값이 비어 있는지만 확인해 취소 가능 여부를 판단합니다.
이렇게 값 하나로 정리하면서, 취소 불가 상태가 된 주문을 다시 취소 가능 상태로 되돌릴 수도 있게 됐습니다. 오늘드림에서는 배차가 잡힌 뒤에도 배달대행사가 배송 취소 콜백을 보내거나 대안 배송으로 전환되는 일이 있습니다. 상태 코드가 앞으로만 흐르던 예전 구조에서는 이런 주문을 고객이 직접 취소할 수 없는 상태로 남겨 둔 채, 매장 마감까지 기다렸다가 배치가 일괄 취소해 주는 수밖에 없었습니다. 지금은 시점 값을 다시 비우기만 하면 고객이 직접 취소할 수 있는 상태로 돌아옵니다.
물류가 지금 무엇을 하고 있는지 알아야 했다
발행되지 않던 피킹 완료 신호
센터배송의 취소 마감 시점을 피킹 완료로 옮기려면, 피킹이 언제 끝났는지를 배송 시스템이 알아야 합니다. 물류 시스템과 배송 시스템 사이에는 이미 Kafka 파이프라인이 깔려 있었고, 출하 지시(할당)가 끝났다는 실적 이벤트가 그 위로 흐르고 있었습니다. 배송 시스템이 물류 이벤트를 실시간으로 받는 구조는 이미 있었습니다.
문제는 필요한 신호가 아예 발행되지 않고 있었다는 점입니다. 배송 시스템이 받고 있던 가장 늦은 신호가 할당 실적이었기 때문에, 할당 실적을 받는 시점에 취소를 막을 수밖에 없었습니다. 취소 마감 시점이 할당에 있던 이유가 이것입니다. 그래서 물류 시스템이 피킹 실적 토픽을 새로 발행하고, 배송 시스템이 이를 구독하는 컨슈머를 붙이기로 했습니다.
물류 시스템 피킹 실적 발행 → Kafka 토픽(신규) → 배송 시스템 컨슈머(신규) → 취소 불가 일시 기록기존 할당 실적 흐름은 손대지 않았습니다. 토픽 하나와 컨슈머 하나가 늘어난 것뿐이어서 다른 흐름에는 영향이 없었습니다. 이벤트 기반으로 결합도를 낮춰 둔 구조가 여기서 효과를 냈습니다. 두 시스템이 동기 API로 묶여 있었다면 취소 판단 시점을 바꾸는 일은 호출 규약을 고치고 그 뒤에 연결된 흐름을 전부 다시 검증하는 작업이 됐을 겁니다. 물류 시스템은 피킹 완료 이벤트를 발행하기만 하고 누가 받는지는 신경 쓰지 않는 구조였기 때문에, 새 신호를 하나 더 얹는 것으로 끝났습니다.
그런데 피킹 완료 이벤트가 오지 않는다면?
토픽을 붙이고 나서 문제가 드러났습니다. 피킹 완료와 출고 확정 사이 리드 타임이 아주 짧은 주문에서, 피킹 완료 이벤트가 누락되고 출고 확정만 도착하는 경우가 있었습니다. 단순 누락으로 끝나지 않고 사고로 이어지는 문제였습니다. 피킹 완료를 못 받으면 취소 불가 일시가 비어 있는 채로 남고, 그 사이 고객이 취소를 누르면 이미 센터를 떠난 상품에 취소가 성립합니다. 앞서 안전장치의 이유로 들었던 바로 그 상황입니다.
그래서 취소를 막는 장치를 하나 더 달았습니다. 출고 확정 이벤트를 받을 때에도 취소 불가 일시를 채웁니다. 피킹 신호가 오지 않았더라도 출고 확정은 반드시 오니까요. 그래도 출고 확정 이벤트가 도착하기 전까지는 짧은 틈이 남습니다. 사고 가능성을 최소화하려고 이 틈도 막았습니다. 고객이 취소를 누르면 택배사에서 실제로 취소할 수 있는 상태인지 먼저 확인하고, 그 사이에 들어온 취소는 모니터링으로 따로 잡아냅니다.
반대 방향도 있었습니다. 이미 취소된 주문에 출고 실적이 뒤늦게 도착하는 경우입니다. 이런 건은 조용히 버리지 않고 불일치 건으로 남겨 확인 대상으로 만들었습니다.
배차와 취소가 겹치는 순간을 분산 락으로 막다
오늘드림은 사정이 달랐습니다. 여기까지가 물류센터에서 나가는 주문 이야기였다면, 오늘드림은 매장에서 포장이 끝나면 배달대행사에 배차를 요청하고 라이더가 픽업해 고객에게 전달하는 구조입니다. 신호를 제때 받는 것만으로는 끝나지 않았습니다. (연동 방식 자체는 올리브영 테크블로그의 배달대행사 API 연동과 장애 대응 포스트에서 자세히 다뤘습니다.)
새로 생긴 동시 요청 구간
취소 마감 시점이 '접수 확정'에서 '배차'로 밀리면서 없던 구간이 생겼습니다. 예전에는 매장이 주문을 접수 확정하는 순간 취소가 막혔기 때문에, 매장이 포장을 마치고 배차를 요청할 때는 이미 취소할 수 없는 주문이었습니다. 이제는 매장이 배차를 요청하는 바로 그 순간에도 고객이 취소를 누를 수 있습니다. 두 요청이 거의 동시에 들어오면, 어느 쪽이 먼저 처리되든 문제가 생깁니다.
취소가 아주 조금 먼저 도착하면 시스템은 아직 배차가 없는 상태에서 배차 취소를 호출합니다. 취소할 대상이 없으니 아무 일도 일어나지 않고, 곧이어 배차 요청이 도착해 라이더가 정상 배정됩니다. 주문은 취소됐는데 라이더는 매장으로 향하고, 매장에는 내줄 상품이 없습니다. 배차 기록도 그대로 남아 정산과 재고가 어긋납니다. 순서가 반대여도 곤란합니다. 배차 처리 중에 취소가 들어오면 아직 배차 번호가 발급되기 전이라 취소할 대상을 못 찾은 채 고객에게는 "취소 완료"라고 답하게 됩니다. 그 뒤 배차가 완료되면 결과는 앞의 경우와 같습니다.
주문번호 단위 Redis 분산 락
두 사례 모두 같은 주문에 대한 배차와 취소가 동시에 진행되면서 생긴 문제입니다. 그래서 같은 주문의 배차와 취소는 한 번에 하나만 진행되도록 순서를 강제할 방법이 필요했고, 아래 세 가지 방식을 비교했습니다.
| 제어 방식 | 검토 내용 | 채택 |
|---|---|---|
| DB 비관적 락 | 주문 행을 잠가 순서를 강제합니다. 다만 이 구간에는 외부 API 호출이 포함되어 있어, 외부 응답이 지연되는 동안 DB 커넥션과 락이 함께 점유됩니다. | ❌ |
| 낙관적 락 + 재시도 | 충돌을 감지한 뒤 되돌리는 방식입니다. 그런데 이미 배달대행사로 나간 호출은 되돌릴 수 없어, 감지 시점에는 이미 늦습니다. | ❌ |
|
Redis 분산 락
|
주문번호 단위로 락을 잡되, 뒤에 온 접수 요청을 기다리게 하지 않고 재시도로 미룹니다. DB 자원을 점유하지 않고, 여러 서버에 걸쳐 동작하며, TTL로 교착을 막을 수 있습니다.
|
✅ 채택
|
락은 고객 취소 처리와 배달대행사 접수 호출, 이 두 곳에만 주문번호 단위로 겁니다. 고객 취소가 먼저 락을 잡은 경우를 따라가 보겠습니다. 뒤이어 배달대행사에 접수를 호출하려던 쪽은 락을 확인하고 "이 주문은 지금 취소 처리 중"이라고 판단합니다. 여기서 접수를 강행하지 않고, 재시도 대상으로 적어 둔 뒤 물러납니다.
잠시 뒤 재시도가 돌 때는 평소의 접수 로직을 그대로 탑니다. 그 로직에는 이미 취소 여부를 확인하는 단계가 들어 있고, 그 사이 취소는 확정됐을 테니 배달대행사에는 접수 요청이 아예 나가지 않습니다. 되돌릴 필요가 없도록 애초에 내보내지 않는 쪽을 택한 것입니다. 외부로 나간 호출은 DB 트랜잭션처럼 롤백되지 않아서, 나간 뒤에 취소 요청을 한 번 더 보내 상쇄하는 것보다 나가기 전에 멈추는 편이 안전합니다.
배차 접수가 먼저 락을 잡은 경우는 반대입니다. 이때 고객이 취소를 누르면 잠시 후 다시 시도해 달라고 안내합니다. 접수가 끝난 뒤 다시 누른 취소는 이미 잡힌 배차를 되돌리는 방식으로 처리됩니다.
배달대행사 응답이 제각각이거나 실패해도 취소는 완료되어야 한다
이미 배차가 잡힌 뒤에 취소가 들어오면, 취소를 확정한 뒤 배달대행사에 배차 취소를 따로 요청해야 합니다. 이미 나간 요청을 뒤에서 되돌리는 보상 동작이라, 이번에는 그 동작의 신뢰도가 문제였습니다. 배달대행사가 제대로 응답해야 취소가 끝나는 구조였기 때문입니다.
제각각인 응답을 세 가지로 정규화
첫 번째 걸림돌은 제각각인 응답이었습니다. 여러 배달대행사와 제휴하다 보니 요청 형태도, 상태 코드도, 응답 규약도 회사마다 달랐습니다. 특히 '이미 취소된 건'을 어떻게 응답하느냐가 문제였습니다. 어떤 곳은 성공, 어떤 곳은 오류 코드로 답했고, 같은 회사 안에서도 사유 코드가 새로 추가되곤 했습니다. 이 응답을 그대로 받으면 이미 취소된 건을 계속 재시도하거나, 반대로 잘 취소된 건을 실패로 기록하게 됩니다.
그래서 공통 인터페이스로 감쌌습니다. 표준 모델을 정의하고 회사별 어댑터가 각자의 스펙을 번역합니다. 응답은 다음과 같은 세 가지로 정규화했습니다. 여기서 핵심은 재시도를 판단하는 코드가 배달대행사 사정을 몰라도 되게 만드는 것입니다. 새 업체가 붙으면 어댑터 하나를, 사유 코드가 늘면 매핑 테이블 한 줄을 더하면 되고, 취소 로직 본체는 그대로입니다.
1. 취소 완료: 방금 취소됐거나, 이미 취소된 상태 → 성공으로 확정하고 재시도하지 않음
2. 취소 불가: 이미 픽업된 경우 등 확정적 거절 → 재시도하지 않고 예외 처리로 넘김
3. 일시적 실패: 타임아웃, 5xx, 네트워크 오류 → 재시도 대상서킷 브레이커와 SQS로 막은 장애 전파
두 번째 걸림돌은 장애 전파였습니다. 외부 API 응답이 늦어지면 그동안 스레드와 커넥션이 함께 묶입니다. 취소와 배차가 자원을 공유하는 오늘드림에서는 취소가 느려지면 배차까지 함께 밀립니다. 그래서 호출 구간에 서킷 브레이커를 두어, 실패율이 임계치를 넘으면 회로를 열고 즉시 빠져나오게 했습니다. 회로가 열린 동안 들어온 취소를 어떻게 처리할지 정하면서, 고객의 취소 확정을 외부 시스템의 성공에 종속시키지 않는다는 원칙을 세웠습니다.
이 원칙은 글 앞부분에서 언급한 해외 커머스의 선택과 정확히 갈리는 지점입니다. Amazon과 eBay는 외부 사정이 불확실하니 고객에게도 "요청"까지만 약속합니다. 저희는 고객에게 확답을 주기로 했으니, 배달대행사 쪽에서 생기는 실패를 고객에게 넘기지 않고 시스템이 떠안아야 했습니다. 고객이 취소를 눌렀고 조건을 충족했다면 그 취소는 우리 시스템 안에서 확정되고, 배달대행사 정리는 그 뒤에 따라오는 일입니다.
회로가 열렸거나 호출이 실패한 건은 메시지 큐인 SQS로 격리하고, 고객에게는 취소 완료로 응답합니다. 배달대행사에 배차 취소를 다시 요청하는 일은 백그라운드 작업이 맡습니다. 재시도가 겹쳐 같은 취소가 두 번 나갈 수도 있는데, 이 중복은 앞서 정리한 응답 정규화가 처리합니다. 이미 취소된 건은 배달대행사가 어떻게 응답하든 '취소 완료'로 읽으니, 몇 번을 다시 보내도 결과가 달라지지 않습니다.
- 처리에 실패하면 SQS가 정해진 횟수만큼 메시지를 다시 전달
- 그 횟수를 넘기면 재시도 테이블에 쌓아 두고 나중에 다시 처리
취소는 한 곳에서 끝나지 않는다
마지막 관문은 취소의 범위였습니다. 오늘드림 주문 하나를 취소하면 매장 POS, 물류 거점, 배달대행사, 재고, 결제가 함께 움직여야 합니다. 대부분 외부 시스템이라 한 트랜잭션으로 묶을 수 없습니다. 그래서 어디까지 갔는지를 건별로 기록하고, 보정 배치가 미완료 건만 다시 처리하도록 했습니다.
의외로 손이 많이 간 건 보정 배치의 대상 조건이었습니다. 조건이 넓으면 이미 처리된 건까지 다시 걸려 이중 취소가 되고, 좁히면 처리돼야 할 건이 빠집니다. 그래서 픽업 주문(고객이 매장에서 직접 받아 가는 주문)처럼 이 흐름을 타면 안 되는 유형을 걸러내고, 결제는 취소됐지만 매장·거점 전송이 남은 건만 정확히 집어내는 작업을 반복했습니다. 눈에 띄는 일은 아니지만 정합성을 실제로 지키는 것은 이 조건입니다.
옮겨 놓은 취소 마감 시점을 지키는 일도 남아 있었습니다. 업체배송의 취소 마감 기준은 송장 등록입니다. 바꿔 말하면 송장이 등록되는 순간 고객의 취소 버튼이 사라집니다. 그러니 이 등록은 제 시점에, 한 번만 이뤄져야 합니다. 그래서 송장 등록 단계에 취소 가능 여부 확인과 중복 송장 검증을 넣었습니다. 기준을 어디에 둘지 정하는 것과, 그 기준이 실제로 그 시점에 지켜지게 만드는 것은 다른 일이었습니다.
되찾은 골든타임은 무엇을 바꿨나
세 배송유형 모두 취소 마감 시점이 실물 출고 직전까지 밀렸습니다. 가장 뚜렷한 변화는 고객센터에 쌓이던 문의가 크게 줄어든 것입니다. 배송 준비 중 취소 관련 고객 문의(VOC)는 평시 약 90%, 문의가 몰리는 세일 기간에도 약 89% 줄었습니다.
- 센터배송: 출하 지시(작업 할당) → 피킹 완료
- 업체배송: 출하 지시 → 송장 등록
- 오늘드림: 주문 접수 확정 → 배차
왜 이만큼 줄었는지는 새로 열린 구간에서 실제로 무슨 일이 벌어지는지를 보면 드러납니다. 개선 후 세일 기간 기준으로, 예전 같으면 막혀 있었을 구간에서 발생하는 취소가 같은 기간 남아 있는 배송 준비 중 취소 문의의 약 세 배입니다. 주문 한 건에 평균 네 개 남짓한 상품이 담겨 있으니, 매일 그만큼의 상품이 선반을 떠나기 전에 제자리에 머무는 셈입니다.
예전에는 이 취소를 처리할 곳이 고객센터뿐이었습니다. 전화로 접수하고, 상담사가 물류에 확인하고, 그마저 어려우면 반품으로 돌리는 경로였습니다. 지금은 같은 건들이 앱에서 버튼 한 번으로 끝납니다. VOC가 열에 아홉 사라진 이유가 여기에 있습니다. 수기 확인도, 반품 절차 안내도, 배송 완료 추적도 함께 사라졌습니다. 문의 한 건마다 들던 상담 응대 비용도 인입량이 줄어든 만큼 그대로 줄었고, 나가지 않아도 될 상품이 나갔다 돌아오던 반품 물류비도 마찬가지입니다.
숫자보다 중요한 건 경로가 바뀌었다는 사실입니다. 예전에는 취소하려면 고객센터를 거쳐야 했고, 그마저도 담당자 확인 결과에 달려 있었습니다. 지금은 고객이 앱에서 버튼을 누르면 끝입니다. 상품이 선반을 떠나기 전까지는, 취소는 협상 대상이 아니라 고객의 권리입니다.
마치며
처음에는 조건 한 단계를 뒤로 미루는 간단한 일이라고 생각했습니다. 하지만 실제로는 판단 기준을 하나로 모으고, 실시간 신호를 받아오고, 새로 생긴 동시성 구간에서 두 요청이 겹치지 않게 하고, 외부 장애를 격리하고, 늘어난 경계 케이스마다 취소를 막는 장치를 다는 일이었습니다. "취소 마감 시점을 늦춘 만큼 안전장치를 촘촘히 둔다"는 것이 이번 프로젝트를 관통한 원칙이었습니다.
해외 커머스가 "취소 요청"이라는 여지를 남겨 둔 데에는 이유가 있었습니다. 즉시 확정을 약속하는 순간, 그 뒤의 불확실성을 전부 시스템이 떠안게 되기 때문입니다. 이 글에서 다룬 분산 락, 응답 정규화, SQS 격리는 그 약속을 지키기 위해 치른 비용이었습니다. 그럼에도 이 비용을 치르기로 한 것은 취소를 실패한 주문으로 보지 않았기 때문입니다. 마음 편히 취소할 수 있다는 확신이 있어야 고객이 다시 주문 버튼을 누른다고 봤습니다.
끝으로, 이 과제는 혼자 한 일이 아닙니다. 주문·결제, 배송·물류, SCM 등 여러 스쿼드가 각자의 자리에서 같은 문제를 붙잡아 주신 덕분에 세 배송유형을 한꺼번에 바꿀 수 있었습니다. 이 자리를 빌려 감사드립니다. 긴 글 읽어주셔서 고맙습니다. 🙇

