수수료율을 크게 내리는 작업이 있었다. 변동 폭이 크면 제한에 걸린다고 들어서 미리 포기해야 하나 싶었다.
Table of contents
Open Table of contents
상황 — 한 번에 내릴 수 있는가
한 번에 못 내리면 rate 를 여러 번 나눠서 내려야 한다.
나누면 그만큼 일정이 늘고 중간 상태로 며칠을 보내게 되므로 그 제한이 정확히 어디서 검사되는지부터 찾기로 했다.
제한이 있다는 말만 듣고 계획을 맞추면 없는 제약에 맞춰 일하게 되고 있는지보다 어디서 어떻게 걸리는지가 계획을 정한다.
원인 — 검사는 실행기에 있었다
값을 받는 컨트롤러부터 봤다.
public function modify(Request $request)
{
$this->service->modifyRate($id, $request->rate);
return response()->json(['success' => true]);
}
modify 에는 검증이 없이 modifyRate 로 넘긴다.
public function modifyRate($id, $rate)
{
$item->rate = $rate;
$item->save();
$this->addHistory(...);
}
modifyRate 에도 없고 save 와 addHistory 만 한다.
더 내려가서 작업 실행기를 봤다.
private function checkOverPlusRate($item)
{
if ($item->option_rate * 2 > $item->base_rate) {
return false; // 연동 안 함
}
return true;
}
checkOverPlusRate 가 호출 시점이 아니라 작업이 도는 시점에 검사하고 있었다.
modify 에 없다고 검증이 없다고 판단했으면 틀렸을 것이고 각 층을 순서대로 끝까지 따라가야 어디에 있는지가 나온다.
비교 — 무엇과 무엇을 견주는가
검사 내용도 예상과 달랐다.
[예상] 변경 전 값 vs 변경 후 값
[실제] 하위 값 vs 상위 값
option_rate 와 base_rate 를 견주지 변경 전후의 차이를 보지 않는다.
크게 내려도 option_rate 와 base_rate 의 관계가 유지되면 통과한다. 무엇을 견주는지 확인 안 했으면 나눠 내리는 계획을 세웠을 것이다.
제약 — 조용히 걸린다
여기서 두 가지가 함께 정리됐다.
변동 폭이 커도 modify 는 통과하므로 미리 나눌 필요가 없고 반대로 호출이 성공해도 반영이 보장되지 않는다.
API 성공
↓
작업 생성
↓
실행 시점에 조용히 걸림
↓
반영 안 됨
checkOverPlusRate 가 false 를 돌려주면 그 건을 연동하지 않고 넘어간다.
오류를 안 던지니 부르는 쪽은 아무 신호도 못 받는다. 사용자가 보는 것은 성공인데 실제로는 반영이 안 된 상태다.
검증 — 작업 실행 결과
그러면 응답으로는 확인이 안 된다.
SELECT status, last_log FROM jobs WHERE ... ORDER BY id DESC LIMIT 10;
jobs 의 status 와 last_log 를 봐야 실제로 돌았는지 알 수 있다.
검증이 어디 있는지를 알고 나니 무엇을 보고 확인할지도 함께 정해졌고 검증의 위치가 확인 방법을 정하는 셈이다.
대상 상태에 따른 적용
이 검사가 모든 대상에 걸리는 것도 아니었다.
등록 안 됨 → 실행할 작업 자체가 없음
↓
이 체크와 무관
등록 안 된 대상은 jobs 에 행이 안 생기니 checkOverPlusRate 도 안 돈다.
같은 요청이 대상의 상태에 따라 다르게 처리되므로 우리가 바꾸려던 것들이 어느 상태인지를 먼저 세어 보고 계획을 확정했다.
왜 이런 구조인지도 짐작이 된다. modify 는 값만 저장하고 반영은 나중에 도는 작업이 하므로 무거운 검증을 그쪽으로 미룬 것이다. 그러면 호출 성공의 뜻이 접수됐다는 데까지로 좁아진다.
정리
- 검증이 호출 시점이 아니라 실행 시점에 있을 수 있다
- 컨트롤러에 없다고 검증이 없다고 판단하면 틀린다
- 각 층을 순서대로 끝까지 따라간다
- 비교 대상이 통념과 다를 수 있다
- 변동 폭이 아니라 다른 두 값의 관계를 볼 수도 있다
- 제한이 있다는 말만 듣고 맞추면 없는 제약에 맞추게 된다
- 변동 폭이 커도 호출은 통과한다
- 반대로 호출 성공이 반영을 보장하지 않는다
- 실행 시점 검증은 오류 없이 조용히 걸린다
- 확인은 응답이 아니라 작업 실행 결과로 한다
- 대상의 상태에 따라 적용 여부가 갈린다