외부 호출이 나가는 경로를 새 것으로 바꿔야 했다. .env 의 주소를 바꾸고 config:cache 로 설정 캐시를 다시 만들고 tinker 에서 config() 로 값이 실제로 바뀌었는지 조회까지 해서 새 값을 확인했다. 그런데 새 경로의 access.log 에는 아무것도 안 들어오고 옛 경로로만 계속 나가고 있었다.
Table of contents
Open Table of contents
원인 — 캐시가 바꾸는 것과 안 바꾸는 것
그 호출을 실제로 하는 것은 상시 떠 있는 queue:work 프로세스였다. 큐에 쌓인 일을 계속 꺼내 처리하는 것들인데 이 프로세스들은 뜰 때 설정을 메모리에 읽어 놓고 그 뒤로는 파일을 다시 보지 않는다. Laravel 공식 문서의 큐 항목도 워커가 오래 사는 프로세스라 뜬 뒤의 코드 변경을 알지 못하므로 배포 때 queue:restart 로 재시작하라고 적어 뒀다.
설정 캐시를 다시 만드는 것은 bootstrap/cache/config.php 를 갱신하는 작업이므로 이미 떠 있는 프로세스의 메모리에는 아무 영향이 없다. 몇 주 전에 뜬 프로세스라면 몇 주 전의 값을 그대로 쓰고 있다. 재시작에는 두 가지 방법이 있었는데 supervisorctl restart 로 워커를 바로 내리는 것과 queue:restart 로 지금 잡은 작업을 끝낸 뒤 스스로 내려가게 하는 것이다. 뒤쪽을 골랐다. 이유는 처리 중인 작업을 중간에 끊으면 그 건이 실패로 남아서다. 대신 워커마다 내려가는 시점이 달라 몇 분 동안 옛 값과 새 값이 섞여 나가는 것을 감수했다. 근거는 queue:restart 가 신호만 보내고 각 워커가 지금 작업을 끝내는 시점은 제각각이라는 점이다. 워커가 다시 뜨니 그때서야 새 경로로 나갔다.
교훈 — 확인 지점의 오류
여기서 잘못한 것은 확인 방법이었다. config() 로 조회했을 때 새 값이 나온 것은 맞지만 그 조회는 새로 뜬 tinker 프로세스에서 한 것이고 새로 뜨면 당연히 새 값을 읽는다. 실제로 일을 하는 프로세스는 옛날에 뜬 것들이며 그것들이 무슨 값을 쓰는지는 그 조회로 알 수 없다.
행위를 확인하고 결과를 확인하지 않았다. 설정을 바꾼 것과 캐시를 만든 것과 값이 보이는 것은 전부 행위 쪽이고, 결과는 새 경로로 트래픽이 흐르는가다.
같은 형태의 반복
같은 구조를 여러 번 만났다. 외부가 번호를 다시 발급한 경우가 하나였다. 한 항목의 배송일을 연장하니 나머지가 분리되면서 새 order_no 를 받았는데 우리 쪽 orders 에는 수집 시점의 옛 번호가 남아 있어 이미 없는 번호로 계속 요청했다. 상대 쪽 장애처럼 보였지만 우리가 가진 값이 낡은 것이었다.
나가는 주소를 바꾼 경우도 있었다. 공유 NAT 게이트웨이로 옮겼더니 특정 마켓 호출이 전부 403 으로 거부됐는데 인증 정보도 이미지도 그대로였고 나가는 IP 만 바뀌었다. 그 마켓은 IP 등록 기반 접근 제어를 쓰고 있었고 우리 문서에는 등록이 필요 없다고 적혀 있었다.
셋 다 같은 모양이다. 내가 가진 값과 실제로 쓰이는 값이 다르고 그 차이는 내가 확인한 자리에서는 안 보인다.
판단 기준 — 쓰이는 자리에서의 확인
확인은 바꾼 자리가 아니라 쓰이는 자리에서 한다. 설정이면 그 설정으로 나가는 트래픽을 보고 새 경로의 access.log 에 curl 로 찔러 본 것 말고 실제 작업 호출이 찍히는지 확인한다.
번호나 식별자면 상대 쪽 API 에 조회해 지금 값이 무엇인지 받아 우리 orders 의 값과 대조한다. 접근 제어면 등록된 곳과 등록 안 된 곳 둘 다에서 호출해 본다. 등록된 쪽이 되고 등록 안 된 쪽이 막혀야 통과했다는 것이 확정되고, 등록 안 된 쪽에서도 되면 그 확인은 아무것도 가르지 못한 것이다.
되돌릴 수 있는 전환
나가는 IP 를 바꿀 때 구 경로를 먼저 내리지 않은 것이 도움이 됐다. 새 경로에서 403 이 나자 바로 옛 경로로 되돌렸고 즉시 정상화됐는데 그 즉시성이 원인을 확정해 줬다. 다른 것이 다 같은 상태에서 주소만 바꿨더니 막혔고 되돌리니 풀렸으면 주소가 원인이다.
구 경로를 이미 지웠으면 이 확인이 불가능했다. 전환은 새 경로에서 먼저 실측하고 그때까지 구 경로를 유지한다.
정리
- 설정 캐시는 파일만 바꾸고 떠 있는 프로세스의 메모리는 안 건드린다
- 새로 뜬 프로세스에서 값을 조회하는 것은 확인이 아니다
- 일을 하는 것은 옛날에 뜬 프로세스들이다
- 행위의 성공을 결과의 성공으로 삼지 않는다
- 확인은 바꾼 자리가 아니라 쓰이는 자리에서 한다
- 내가 가진 식별자가 낡았을 수 있으므로 상대에게 물어 대조한다
- 접근 제어 통과는 등록 안 된 곳이 막히는 것까지 봐야 확정된다
- 전환은 구 경로를 유지한 채 신 경로에서 먼저 실측한다