본문으로 건너뛰기

Pack 1 집계 스크립트 자동화 가이드

ADR 0012 S1 및 0017 후속. 다음 3개 aggregator 를 Cloud Scheduler + Cloud Functions 경유로 하루 1회 자동 실행한다.

  • scripts/aggregate-docgen-stats.ts — docgenEvents → stats.docgen.*
  • scripts/aggregate-related-memories-stats.ts — relatedMemoriesEvents → stats.relatedMemories.* (ADR 0017 V2 필드 포함)
  • scripts/aggregate-embedding-coverage.ts — legacyDocuments → stats.embedding.* (ADR 0017 · #580)

1. 현 상태 (2026-04-24)

  • 3 스크립트 모두 수동 실행 — NODE_PATH=apps/web/node_modules npx tsx scripts/aggregate-*.ts
  • Firebase Admin 초기화 완료 (scripts/lib/admin.ts)
  • 30일 롤링 윈도우 (docgen · relatedMemories) · 순간 스냅샷 (embedding coverage)

제약:

  • 수동 실행 → 집계 간극 발생 시 대시보드 데이터 stale
  • Cloud Functions 으로 승격 시 실행 환경 제약 (파일시스템 접근 없음, 60s 타임아웃)

2. 권장 아키텍처

옵션 A: Cloud Functions scheduled

Cloud Scheduler (cron "0 4 * * *" KST)
→ Pub/Sub topic: pack1-stats-aggregate
→ Cloud Function: aggregateStats (Gen2)
→ 내부에서 aggregate-docgen-stats 로직 호출
→ 내부에서 aggregate-related-memories-stats 로직 호출

장점: 한 스케줄러로 두 집계 동시 실행. 실패 시 알림 단일 경로. 단점: Cloud Functions Gen2 메모리 · 타임아웃 설정 필요. 다 테넌트 순회 시 540s 상한 접근.

옵션 B: GitHub Actions scheduled workflow

.github/workflows/aggregate-stats.yml
- cron: "0 19 * * *" # UTC 19:00 = KST 04:00
- firebase-admin credentials via GitHub Secret
- NODE_PATH=apps/web/node_modules npx tsx scripts/aggregate-*.ts

장점: 기존 스크립트 그대로 재사용. Cloud 환경 설정 최소. 단점: GH Actions 실행 시간 제한 (6h), 시크릿 관리 부담.

옵션 C (권장): 옵션 A 의 간소화

  • 단일 Cloud Function aggregatePack1Stats (Gen2, 540s, 1GB)
  • 내부에서 두 집계 로직 순차 실행
  • 실패 시 Sentry/Slack 알림 (기존 infraHardening 네임스페이스 활용)

3. Cloud Function 스켈레톤 (미구현, 후속 PR)

// functions/src/aggregate-pack1-stats.ts
import { onSchedule } from "firebase-functions/v2/scheduler";
import { getFirestore, FieldValue } from "firebase-admin/firestore";

export const aggregatePack1Stats = onSchedule(
{
schedule: "0 4 * * *", // KST 04:00
timeZone: "Asia/Seoul",
memory: "1GiB",
timeoutSeconds: 540,
retryCount: 2,
},
async () => {
const db = getFirestore();
const tenants = await db.collection("tenants").get();
for (const t of tenants.docs) {
await aggregateDocgenForTenant(t.id, db);
await aggregateRelatedMemoriesForTenant(t.id, db);
await aggregateEmbeddingCoverageForTenant(t.id, db);
}
},
);

주의: scripts/lib/admin.ts 와 Cloud Functions SDK 초기화 방식이 다름 → 로직 추출 리팩터 필요 (packages/pack1-stats 로 승격 검토).


4. 배포 순서

  1. 관측 페이즈 (현재): 수동 실행, 1주 1회
  2. Cloud Functions 이전 PR: 옵션 C 구현, Functions emulator 로 검증
  3. 알림 연결 PR: 실패 시 ops-console 감사 로그 + Slack webhook
  4. Gone: 수동 스크립트는 scripts/ 유지 (재인덱싱·긴급 복구용)

5. 경보 임계값 (pack1-metrics.md 참조)

  • docgen: template_invalid > 5% · render_failed > 1% · avgElapsedMs > 3000ms
  • relatedMemories: C 캐시 재평가 3 조건 (CTR / weight / cancel)

Cloud Function 내부에서 임계 초과 시 ops-console alerts 컬렉션에 write.


6. 관련 문서