Ethan Hur's blog

시간 관련 디버깅

2017-12-05

시즌제로 운영되는 컨텐츠가 있었는데, 기존에는 시즌이 간격을 두고 진행되다가 1달마다 상시 진행되는 것으로 바뀌었다.

근본적인 원인은 시즌마다 새로 row를 따지 않고 같은 row 에 덮어쓰기 하는 방식으로 데이터 구조를 설계했던 것이라고 생각한다. (데이터 덮어쓰기는 정말 지양해야 한다 ㅠㅠ)

라이브에 올라간 이상 데이터 구조를 바꾸는 것은 너무 큰 작업이므로 다른 방법을 도입하기로 했다.

문제가 되는 코드는 다음과 같았다.

1
2
3
4
5
SELECT * FROM contents_season WHERE begin < NOW() AND NOW() < end;
// 시즌이 존재했을 경우 비즈니스 로직 처리
UPDATE user_contents SET completed_date = NOW() WHERE user_id = XXXX;

위의 쿼리와 아래 쿼리 사이의 시간 간격이 존재하는데, 그 간격 사이에 달이 바뀐 경우, completed_date 가 다음 달로 찍히게 되어 데이터 정합성이 안 맞는 문제가 있었다.

이를 해결하기 위해서는 DB에서 시간을 select 해오고, 그 시간을 기준으로 처리하는 방법이 있다.

1
2
3
4
5
6
7
cur_time = time.time() // python 기준
SELECT * FROM contents_season WHERE begin < (cur_time) and (cur_time) < end;
// 비즈니스 로직 처리
UPDATE user_contents SET completed_date = (cur_time) WHERE user_id = XXXX;

조금만 생각해보면 문제점을 알 수 있으나, Production에 올라가지 않고 테스트 환경에서는 지나치기 쉬운 실수라고 생각하여 정리했다.

DB에서 시간을 select 해와서 처리할 수도 있지만, 특별히 서버 인스턴스 별 sync 가 중요하지 않은 이상 network 를 왔다가면서 처리할 필요는 없을 것 같다.

또한, DB와 서버의 시간도 100프로 동기화되어 있다는 보장이 안되어 있으므로 둘 중 하나만 써야 한다는 점도 짚고 넘어가자.

여담

좋지 못하다고 생각되는 코드를 디버깅하는 것은 썩 즐거운 일은 아니다.

하지만 일을 하면서 그러한 디버깅을 피할 수 없고, 차라리 이를 통해 기초적인 내용을 remind 하는 기회가 있다고 생각하는 것이 편할 것 같다.

Tags: Mysql