- 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
GAS 6분 실행 한도: 멈추기 전에 끊어서 재개하라
Apps Script는 한 번 실행이 6분에서 강제 종료된다. 대량 작업은 청크 + 커서 + 시간 트리거 재개로 설계해야 절반만 처리되는 사고를 막는다.
한 번의 실행은 6분에서 강제로 끊긴다. 1만 행을 한 루프에서 처리하려다 6분에 걸리면, 스크립트는 중간에 죽고 절반만 처리된 상태로 남는다. 다시 돌리면 처리한 행을 또 건드린다.
왜 중요한가
절반만 반영된 데이터는 안 한 것보다 위험하다. 어디까지 됐는지 모르니 수동 복구가 필요하고, 그 시간이 자동화로 아낀 시간을 그대로 까먹는다. 트리거 총 실행시간도 별도 한도가 있다(소비자 계정 약 90분/일).
정답: 청크 + 커서 + 트리거 재개
한 번에 끝내려 하지 말고, 처리한 위치(커서)를 저장하고 시간 트리거로 다음 청크를 이어서 돌린다.
const JOB_KEY = "sync.cursor";
function runSyncJob() {
const lock = LockService.getScriptLock();
if (!lock.tryLock(10000)) return; // 겹침 방지
try {
const props = PropertiesService.getScriptProperties();
const cursor = Number(props.getProperty(JOB_KEY) || 0);
const result = processChunk(cursor, 300); // 한 번에 300행
if (result.done) {
props.deleteProperty(JOB_KEY);
deleteTriggers_("runSyncJob"); // 끝나면 트리거 정리
return;
}
props.setProperty(JOB_KEY, String(result.nextCursor));
scheduleOnce_("runSyncJob", 60 * 1000); // 1분 뒤 재개
} finally {
lock.releaseLock();
}
}
function scheduleOnce_(handler, delayMs) {
deleteTriggers_(handler);
ScriptApp.newTrigger(handler).timeBased().after(delayMs).create();
}
function deleteTriggers_(handler) {
ScriptApp.getProjectTriggers()
.filter((tr) => tr.getHandlerFunction() === handler)
.forEach((tr) => ScriptApp.deleteTrigger(tr));
}
놓치기 쉬운 것
- 트리거를 꼭 지워라. 트리거는 스크립트당 20개 한도다. 1회용 트리거를 만들기 전에 같은 handler의 기존 트리거를 먼저 삭제하지 않으면 금방 한도에 부딪힌다.
- 겹침 방지. 트리거가 이전 실행과 겹쳐 같은 커서를 두 번 처리하지 않도록
LockService를 함께 쓴다. - 종료 정리. 끝나면 커서와 트리거를 반드시 지운다. 안 그러면 빈 작업이 매분 돈다.
깊이: 청크 크기는 측정해서 정한다
청크 크기는 100~500행에서 시작해 실제 실행 시간을 보며 조정한다. 한 청크가 6분의 절반을 넘으면 줄인다. 핵심 한 줄: 6분 안에 끝날 단위로 쪼개고, 위치를 저장하고, 이어서 돌려라.
자주 묻는 질문
- Google Apps Script 실행이 6분에서 멈추는 이유는?
- Apps Script는 한 번의 실행을 약 6분에서 강제 종료합니다(소비자 계정 기준). 대량 작업을 한 루프로 처리하다 한도에 걸리면 스크립트가 중간에 죽어, 데이터가 절반만 반영되는 사고가 납니다.
- 6분 실행 한도를 어떻게 우회하나요?
- 한 번에 끝내려 하지 말고, 처리한 위치를 커서로 저장한 뒤 시간 기반 트리거로 다음 청크를 이어서 실행합니다(청크 + 커서 + 트리거 재개). LockService로 실행 겹침도 막습니다.
- 트리거로 돌리면 시간 제한이 없나요?
- 아니요. 트리거 총 실행시간에도 별도 한도가 있습니다(소비자 계정 약 90분/일). 청크 크기와 실행 빈도를 그 한도 안에서 설계해야 합니다.
- 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