힘든 한 주였다. 일이 바쁘기보단 하루하루 꽉차게 교훈을 얻었다. 요즘 일상이 평온하니 조금 나른해졌다. 안좋은 일은 동시에 찾아오고 장애와 버그는 예고없이 찾아온다.
상쾌한 월요일 아침, 서비스가 내려갔다. 결론부터 말하자면, 클러스터 구조에서 서버가 단일 DB이랑만 연결되어 있었다. 그러면서 스팩업을 하면서 읽기 전용으로 연결된 DB가 내려가고 전체 서비스가 마비됐다. 스펙업이 끝나고 서버 재기동하여 정상화 됐다.
이중화 되어있는 구조에서 스팩업은 리스크가 적다. 읽기 전용 DB가 잠시 내려가더라도 이중화 되어있기 때문에 서비스에 영향을 주지 않는다. 이런 안일한 생각이 장애로 이어졌다. AWS 엔드포인트는 주소가 길어서 내용을 놓치기 쉽다. 당연히 잘 돌아가고 있었으니까 문제가 없겠지. 안일했다.
지금까지 장애 하나 없이 잘 돌았다고 해도 엔드포인트 확인을 자세히 하지 않은 점은 명백한 실수다. 적어도 작업하기 전 정!말! 이중화가 되어있는지 확인하고 했어야 했다. 억울하지만.. 인생은 원래 불공평하다. 꼼꼼히 확인하지 않은 것은 명백한 실수다. 특히 DevOps 작업의 이중화 관련된 내용은 좀 더 꼼꼼히 다가가야 한다.
이 버그는 거의 10일이나 있었던 버그다. 다른 작업들로 꽤 바빴던 시기여서 오래갔던 것 같다. 가장 큰 문제는 재현이 안됐다. 재현은 되지 않았지만 특징이 있었다.
이 문제는 로컬 환경에서는 괜찮다는 점에서 찾았다. 특히 찜찜했던 코드였던 toLocaleString() 이 부분에 주목했다. locale 이라면 지역의 의미를 가지고 있다. (메소드 이름 참 명시적이다😍) 어떤 지역은 날짜 표기를 Year-Month-Day 이지만 어떤 지역은 Month-Day-Year 일 수 있다. 여기서 substring 메소드는 문자열을 자르니까.. 명시적이지 못하다. 귀신이.. 아니 버그가 여기 있었구나.
const a = DateTime.fromJSDate(aDate).toLocaleString().substring(0, 8);
const b = DateTime.fromJSDate(bDate).toLocaleString().substring(0, 8);
return a === b
이 자리엔 무조건 이 값이 있어야 된다는 보장이 없는 코드들에서 항상 버그가 생긴다. 명시적이지 않은 코드가 누적 될 수록 무슨 의미인지 한참 생각해야 된다. 그만큼 시간이 오래 걸릴 수 있다. 모든 문서를 다 읽고 작업해야 한다는 것일까?
나는 적어도 내가 사용하는 함수에 한해서는 어떤 기능을 가지고 있는지 알아야 한다고 생각한다. 적어도 그런 노력은 해야한다. 문제가 생기지 않더라도 미래에 문제가 생길 수 있다면, 그 미래에 발생할 작업까지 비용(시간)으로 생각해야 한다. 정리와 청소가 귀찮아 하지 않았던 방에는 어쩌면.. 아주 어쩌면 작은 유령이 살 지도 모르는 일이니까.
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/toLocaleString