Haeminway haeminway
English
기술 노트로
2 분 분량

PropertiesService는 데이터베이스가 아니다: 9KB의 벽

Properties 값은 한 개당 약 9KB가 한계다. 캐시는 유실돼도 되는 데이터에만. 큰 상태는 Sheet·Drive·외부 DB로. JSON 직렬화는 타입을 잃는다.

PropertiesService는 작은 저장소이지 데이터베이스가 아니다. 값 하나당 약 9KB, store 전체도 한계가 있다. 커서·작은 설정·idempotency key 정도만 두고, 그 이상은 다른 저장소로 보낸다.

왜 중요한가

“상태를 Properties에 JSON으로 저장”으로 시작하면, 데이터가 커진 어느 날 9KB에서 조용히 실패한다. 게다가 캐시에만 둔 상태는 TTL이 지나면 사라진다. 유실되면 안 되는 데이터를 휘발성 저장소에 두는 것이 사고의 시작이다.

저장소 선택 규칙

저장소용도한계
CacheService유실돼도 되는 가속용 캐시키당 100KB, TTL 기반
PropertiesService커서·설정·플래그값 ~9KB
Sheet사용자에게 보이는 표 형태 상태셀 5만 자
Drive JSON큰 불투명 상태(파일 관리 필요)파일 크기
외부 DB다수 사용자·쿼리 많은·대량

핵심: 데이터를 잃어도 되는가? 그 답이 CacheService와 나머지를 가른다.

JSON 직렬화는 타입을 잃는다

JSON.stringify()/parse()만으로는 Date·Map·Set·undefined·NaN이 안전하게 복원되지 않는다.

// Date를 ISO 문자열로 저장, 읽을 때 복원
const replacer = (k, v) => (v instanceof Date ? { __d: v.toISOString() } : v);
const reviver = (k, v) => (v && v.__d ? new Date(v.__d) : v);

props.setProperty("job", JSON.stringify(state, replacer));
const state = JSON.parse(props.getProperty("job") || "{}", reviver);

깊이: 100KB 넘는 캐시는 분할

CacheService 키 하나는 100KB 한계다. 더 크면 청크로 쪼개 여러 키에 나눠 담고, 재조립 키를 둔다. 단 캐시는 항상 재생성 경로가 있어야 한다.

핵심 한 줄: 작은 건 Properties, 휘발은 Cache, 큰 건 Sheet·Drive·DB. 타입은 replacer/reviver로 지켜라.

자주 묻는 질문

PropertiesService에 JSON 상태를 저장하면 왜 문제가 생기나요?
값 하나당 약 9KB 한계가 있어서 데이터가 커지면 조용히 실패합니다. 커서·설정·idempotency key 정도만 두고 큰 상태는 Sheet, Drive, 외부 DB로 보내야 합니다.
CacheService와 PropertiesService는 언제 각각 써야 하나요?
유실돼도 되는 가속용 데이터는 CacheService(키당 100KB, TTL 기반), 유실되면 안 되는 커서나 설정은 PropertiesService(값당 약 9KB)에 둡니다.
JSON.stringify/parse로 저장하면 어떤 타입이 손실되나요?
Date, Map, Set, undefined, NaN은 JSON 직렬화만으로 안전하게 복원되지 않습니다. replacer/reviver를 명시해 타입을 보호해야 합니다.