Skip to content
isdnetworks
Go back

전역 값이 계정마다 저장돼 있었다

분류 자료를 crontab 으로 하루 한 번 받아 오는 작업이 있다. 마지막으로 받은 시각을 어딘가 적어 둬야 했는데 그 값이 api_config 에 들어 있었다.

Table of contents

Open Table of contents

계정마다 값이 갈라졌다

api_configlast_sync_date 컬럼이 붙어 있었다.

CREATE TABLE api_config (
  config_no       INT NOT NULL AUTO_INCREMENT,
  account_name    VARCHAR(50) NOT NULL,
  api_key         VARCHAR(100) NOT NULL,
  last_sync_date  DATETIME NULL,
  PRIMARY KEY (config_no)
);

계정이 세 개라 행이 셋이고 last_sync_date 도 셋이다. 그런데 분류 자료는 계정과 무관하다. 어느 계정으로 받든 같은 자료인데 값만 계정마다 따로 있다.

한 계정으로 받으면 그 행만 UPDATE 되고 나머지는 옛 시각을 들고 있다. 마지막으로 언제 받았느냐를 물으면 답이 세 개가 나온다. 어느 것이 맞는지 판단할 근거가 없다.

이 값이 무엇에 달려 있나

값을 어디에 둘지 정할 때 먼저 물었어야 하는 것이 이것이었다. 계정마다 다른 값이면 계정 테이블에 두고 상품마다 다르면 상품 테이블에 두고 시스템 전체에 하나면 전역 자리에 둔다.

분류 자료 수신 시각은 세 번째다. 계정이 몇 개가 되든 시스템에 하나다. 컬럼이 붙어 있는 테이블이 그 값의 주인이 아니었던 것이다.

전역 자리를 만들었다

이런 값이 더 생길 것 같아서 app_meta 를 만들었다.

CREATE TABLE app_meta (
  meta_key   VARCHAR(50) NOT NULL,
  meta_value VARCHAR(255) NULL,
  upd_date   DATETIME NOT NULL,
  PRIMARY KEY (meta_key)
);

기존 세 행 중 무엇을 옮길지도 정해야 했다. MAX 를 쓰면 그 사이에 받았어야 할 것을 안 받는다. MIN 을 쓰면 이미 받은 것을 다시 받는다. 분류 자료는 덮어써도 되는 것이라 중복 수신이 문제가 안 되므로 MIN 을 골랐다.

INSERT INTO app_meta (meta_key, meta_value, upd_date)
SELECT 'last_category_sync', DATE_FORMAT(MIN(last_sync_date), '%Y-%m-%d %H:%i:%s'), NOW()
FROM api_config WHERE last_sync_date IS NOT NULL;

last_sync_date IS NOT NULL 로 값이 비어 있는 계정은 제외했다. MINNULL 을 무시하지만 조건에 두면 의도가 드러난다. 한 번도 안 받았다는 뜻이라 판단에 쓸 값이 아니었다.

옛 컬럼은 바로 DROP 하지 않았다. grep -rn last_sync_date 로 읽는 코드를 찾아 고치고 그 뒤에 지웠다. 남겨 두면 다음 사람이 그 컬럼을 보고 쓴다. 값이 안 갱신되는 컬럼이 남아 있는 쪽이 더 나쁘다.

키-값 테이블의 함정

편한 대신 조심할 것이 있었다. meta_valueVARCHAR 라 날짜도 문자열로 들어간다. 꺼내서 비교할 때 STR_TO_DATE 를 씌우거나 PHP 쪽에서 변환해야 한다.

키 이름에 오타가 나면 조용히 통과하는 것도 문제였다. 없는 meta_key 를 읽으면 빈 값이 나오고 오류는 안 난다. define 으로 상수에 모아 뒀다.

define('META_LAST_CATEGORY_SYNC', 'last_category_sync');
define('META_LAST_PRICE_SYNC',    'last_price_sync');

아무 값이나 들어갈 수 있어서 이 테이블이 쓰레기통이 되기 쉽다는 것도 봤다. 무엇이 들어 있고 각 키가 무슨 뜻인지 목록을 문서로 남겼다.

정리


Share this post on:

Previous Post
채널마다 형식이 달랐다
Next Post
가격 계산이 두 곳에 있었다