- 2026.07.29 Apps Script 프로젝트가 늘어나면 반드시 망가지는 것들
- 2026.07.16 매일 돌던 Apps Script 트리거가 갑자기 멈추는 이유
- 2026.07.15 브라우저 저장소에 고객정보 넣으면 생기는 문제
- 2026.07.07 브라우저가 내 데이터를 버릴 때: 초록 체크가 거짓말을 한다
- 2026.07.07 설치됨 ≠ 작동함: 백업 트리거가 한 번도 안 돌았다
- 2026.07.07 GAS엔 점진 배포가 없다: '맞는' 검사 하나가 전 사용자를 잠근다
- 2026.07.07 시트가 텍스트를 날짜로 바꾼다: '2026-06'이 완료를 영영 막을 때
- 2026.06.18 여러 사람이 한 시트에 쓰는 점검 앱: 동시성·중복·내보내기 설계
- 2026.06.12 셀을 한 칸씩 읽지 마라: 서비스 호출이 진짜 비용이다
- 2026.06.11 시트 셀에 JSON·이미지를 통째로 넣으면 터진다
- 2026.06.10 웹앱 배포 설정 하나가 보안 모델을 정한다: Execute as / 접근 권한
- 2026.06.09 GAS 6분 실행 한도: 멈추기 전에 끊어서 재개하라
- 2026.06.08 PropertiesService는 데이터베이스가 아니다: 9KB의 벽
- 2026.06.07 모바일에서 화면을 이미지로 저장할 때 멈추는 진짜 이유
- 2026.06.06 동시에 같은 시트를 쓰면 깨진다: LockService와 30 동시 실행 천장 지금 보는 글
- 2026.06.05 재배포할 때마다 주소가 바뀌면 안 된다: /exec URL 고정
- 2026.06.04 외부 호출은 가끔 실패한다: 지수 백오프와 재시도 예산
- 2026.06.03 HtmlService 앱은 껍데기 먼저: 비동기 로드와 모바일 뒤로가기
- 2026.06.02 GAS를 졸업해야 할 때: 한계 신호와 외부 DB 이전
- 2026.06.01 GAS에 지능과 엔진룸을 더하기: Vertex AI와 Cloud Run
동시에 같은 시트를 쓰면 깨진다: LockService와 30 동시 실행 천장
여러 사용자·트리거가 같은 자산을 쓰면 번호가 겹치고 행이 덮인다. tryLock + finally + flush로 막고, 동시 실행 30/user 천장을 설계에 넣어라.
읽기-수정-쓰기가 붙은 작업은 lock으로 감싸라. append, 번호 발급, 상태 변경처럼 “현재 값을 읽고 → 바꿔서 → 쓰는” 작업은, 두 실행이 겹치면 같은 값을 읽어 하나가 덮어쓴다.
왜 중요한가
접수번호가 중복 발급되거나, 동시에 제출한 두 건 중 하나가 사라진다. 평소엔 안 보이다가 사용자가 몰리는 순간 터지므로, 재현이 어렵고 신뢰를 깎는다.
lock 종류와 표준 패턴
| 종류 | 직렬화 범위 |
|---|---|
getScriptLock() | 프로젝트 전체에서 하나의 임계구역 |
getDocumentLock() | 같은 문서 안에서만 (standalone에선 null 가능) |
getUserLock() | 같은 사용자 실행만 |
function issueNumber() {
const lock = LockService.getScriptLock();
if (!lock.tryLock(10000)) throw new Error("lock 획득 실패");
try {
const sheet = SpreadsheetApp.getActive().getSheetByName("Counter");
const next = Number(sheet.getRange("A1").getValue()) + 1;
sheet.getRange("A1").setValue(next);
SpreadsheetApp.flush(); // 해제 전 반드시 반영
return next;
} finally {
lock.releaseLock(); // 항상 finally
}
}
규칙:
tryLock(timeoutMs)을 우선 쓴다(무한 대기 금지).releaseLock()은 항상finally에 둔다.- 해제 전에
SpreadsheetApp.flush()로 쓰기를 확정한다. 안 하면 다음 실행이 옛 값을 읽는다. - lock 안에서는 네트워크 호출·긴 계산·사용자 대기를 하지 않는다.
비멱등 쓰기를 재시도까지 한다면 lock과 멱등키를 함께 쓴다 — lock이 동시 충돌을, 멱등키가 재시도 중복을 막는다.
깊이: 30 동시 실행 천장
같은 사용자 기준 동시 실행은 약 30개가 천장이다. LockService 대기를 고려하면 무손실 동시 사용자는 대략 60명 선으로 설계한다. 그 이상이면 외부 DB나 큐로 넘어갈 신호다. 이 한계는 영업·계약 단계에서 미리 고지하는 게 안전하다.
핵심 한 줄: 공유 쓰기엔 tryLock + finally + flush. 동시 사용자 한계는 미리 설계하라.
자주 묻는 질문
- GAS에서 동시에 같은 시트에 쓰면 왜 데이터가 깨지나요?
- 두 실행이 겹치면 같은 현재 값을 읽어 하나가 다른 하나를 덮어씁니다. 접수번호 중복 발급이나 동시 제출 건 소실이 대표적인 사례입니다.
- LockService를 올바르게 쓰려면 어떤 규칙을 따라야 하나요?
- tryLock(timeoutMs)으로 획득하고, releaseLock()은 반드시 finally에 두며, 해제 전에 SpreadsheetApp.flush()로 쓰기를 확정해야 합니다.
- GAS의 동시 실행 한도는 얼마이며 어떻게 설계해야 하나요?
- 같은 사용자 기준 동시 실행은 약 30개가 천장입니다. LockService 대기를 고려하면 무손실 동시 사용자는 대략 60명 선으로 설계하고, 그 이상이면 외부 DB나 큐로 전환을 검토해야 합니다.
- 2026.07.29 Apps Script 프로젝트가 늘어나면 반드시 망가지는 것들
- 2026.07.16 매일 돌던 Apps Script 트리거가 갑자기 멈추는 이유
- 2026.07.15 브라우저 저장소에 고객정보 넣으면 생기는 문제
- 2026.07.07 브라우저가 내 데이터를 버릴 때: 초록 체크가 거짓말을 한다
- 2026.07.07 설치됨 ≠ 작동함: 백업 트리거가 한 번도 안 돌았다
- 2026.07.07 GAS엔 점진 배포가 없다: '맞는' 검사 하나가 전 사용자를 잠근다
- 2026.07.07 시트가 텍스트를 날짜로 바꾼다: '2026-06'이 완료를 영영 막을 때
- 2026.06.18 여러 사람이 한 시트에 쓰는 점검 앱: 동시성·중복·내보내기 설계
- 2026.06.12 셀을 한 칸씩 읽지 마라: 서비스 호출이 진짜 비용이다
- 2026.06.11 시트 셀에 JSON·이미지를 통째로 넣으면 터진다
- 2026.06.10 웹앱 배포 설정 하나가 보안 모델을 정한다: Execute as / 접근 권한
- 2026.06.09 GAS 6분 실행 한도: 멈추기 전에 끊어서 재개하라
- 2026.06.08 PropertiesService는 데이터베이스가 아니다: 9KB의 벽
- 2026.06.07 모바일에서 화면을 이미지로 저장할 때 멈추는 진짜 이유
- 2026.06.06 동시에 같은 시트를 쓰면 깨진다: LockService와 30 동시 실행 천장 지금 보는 글
- 2026.06.05 재배포할 때마다 주소가 바뀌면 안 된다: /exec URL 고정
- 2026.06.04 외부 호출은 가끔 실패한다: 지수 백오프와 재시도 예산
- 2026.06.03 HtmlService 앱은 껍데기 먼저: 비동기 로드와 모바일 뒤로가기
- 2026.06.02 GAS를 졸업해야 할 때: 한계 신호와 외부 DB 이전
- 2026.06.01 GAS에 지능과 엔진룸을 더하기: Vertex AI와 Cloud Run