AgentSkillsCN

Gas Environment

气体环境

SKILL.md

GAS Environment Skill

Google Apps Script 환경의 특성과 제약사항, 최적화 가이드.

Runtime Limits

제한대응
실행 시간6분 (트리거: 30분)청크 처리, 연속 실행
메모리~1GB대용량 데이터 스트리밍
URL Fetch100MB/호출페이지네이션
스프레드시트 셀1000만 개/파일분할 저장
동시 실행30/사용자큐잉, 지수 백오프

Sheets API 최적화

❌ Bad: 셀 하나씩 접근

typescript
// N번의 API 호출 - 매우 느림
for (let i = 0; i < 100; i++) {
  sheet.getRange(i, 1).setValue(data[i])
}

✅ Good: 범위로 한 번에

typescript
// 1번의 API 호출
sheet.getRange(1, 1, 100, 1).setValues(data.map(d => [d]))

✅ Better: 배치 + 플러시

typescript
// 여러 작업 후 한 번에 적용
const values = []
for (const item of items) {
  values.push([item.id, item.name, item.value])
}
sheet.getRange(1, 1, values.length, 3).setValues(values)
SpreadsheetApp.flush()  // 강제 적용

읽기 최적화

필요한 범위만 읽기

typescript
// ❌ 전체 시트 (빈 셀 포함)
sheet.getDataRange().getValues()

// ✅ 데이터 있는 영역만
const lastRow = sheet.getLastRow()
const lastCol = sheet.getLastColumn()
sheet.getRange(1, 1, lastRow, lastCol).getValues()

// ✅✅ 특정 열만
sheet.getRange("A:C").getValues()  // A~C 열만

캐싱

typescript
// CacheService 활용 (최대 6시간)
const cache = CacheService.getScriptCache()

function getDataCached(key: string) {
  const cached = cache.get(key)
  if (cached) return JSON.parse(cached)
  
  const data = fetchExpensiveData()
  cache.put(key, JSON.stringify(data), 21600)  // 6시간
  return data
}

에러 핸들링

재시도 패턴

typescript
function withRetry<T>(fn: () => T, maxRetries = 3): T {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return fn()
    } catch (e) {
      if (i === maxRetries - 1) throw e
      Utilities.sleep(1000 * Math.pow(2, i))  // 지수 백오프
    }
  }
  throw new Error('Unreachable')
}

// 사용
const data = withRetry(() => sheet.getDataRange().getValues())

Lock으로 동시성 제어

typescript
function updateWithLock(fn: () => void) {
  const lock = LockService.getScriptLock()
  try {
    lock.waitLock(30000)  // 30초 대기
    fn()
  } finally {
    lock.releaseLock()
  }
}

clasp 배포

프로젝트 구조

code
project/
├── src/           # TypeScript 소스
├── dist/          # 빌드 결과 (GAS용)
├── .clasp.json    # clasp 설정
└── appsscript.json

.clasp.json

json
{
  "scriptId": "YOUR_SCRIPT_ID",
  "rootDir": "dist"
}

배포 명령어

bash
# 빌드 후 푸시
pnpm build:gas
clasp push

# 배포 (버전 생성)
clasp deploy -d "v1.0.0"

# 로그 확인
clasp logs

디버깅

console.log vs Logger

typescript
// 둘 다 Stackdriver에 기록
console.log('Debug:', data)     // 추천 (표준)
Logger.log('Debug: %s', data)   // GAS 전용

// 실행 로그 확인
// GAS 에디터 > 실행 > 실행 로그
// 또는: clasp logs

에러 스택 추적

typescript
function main() {
  try {
    riskyOperation()
  } catch (e) {
    console.error('Error:', e.message)
    console.error('Stack:', e.stack)
    throw e  // 다시 던져서 실행 실패로 표시
  }
}

환경 분기

GAS vs Node.js

typescript
// 환경 감지
const isGAS = typeof ScriptApp !== 'undefined'

// 어댑터 선택
const adapter = isGAS 
  ? new GasAdapter() 
  : new MockAdapter()

Properties로 설정 관리

typescript
// 스크립트 속성 (배포 시 설정)
const props = PropertiesService.getScriptProperties()
const spreadsheetId = props.getProperty('SPREADSHEET_ID')

// 사용자 속성 (사용자별)
const userProps = PropertiesService.getUserProperties()

References