배경
현재 개발 프로세스에서 새로운 기능이나 변경사항을 운영 배포 전에 검증할 방법이 없습니다.
현재 흐름:
코드 변경 → main 병합 → Cloudflare Workers 운영 배포 → leetcode-study에서 실제 동작 확인
운영 환경에 배포된 후에야 webhook 동작을 확인할 수 있어서, 문제가 발생하면 실제 스터디 참여자에게 영향을 미칩니다. 최근 3개의 PR이 연속 리버트된 이력(#17, #18, #19)이 이를 잘 보여줍니다.
원하는 흐름:
코드 변경 → 스테이징 배포 → 테스트 PR로 검증 → 확인 완료 → main 병합 → 운영 배포
제약 조건
- 별도 테스트 레포를 만들지 않는다 — 관리 포인트가 늘어나는 것을 최소화
- 기존 leetcode-study 레포 안에서 테스트 가능해야 한다
- 프로덕션 워커 코드에 대한 변경은 최소화한다
선택한 접근 방식
라벨 기반 스테이징 라우팅
leetcode-study 레포에서 테스트용 PR을 생성할 때 staging 라벨을 붙이면, 프로덕션 워커가 해당 이벤트를 스테이징 워커로 포워딩한다.
leetcode-study PR (모든 webhook 이벤트)
│
▼
Production Worker (github.dalestudy.com)
│
├─ staging 라벨 감지?
│ YES ──► Forward ──► Staging Worker (별도 인스턴스)
│ NO ──► 정상 처리
왜 Production을 거쳐야 하는가?
GitHub App의 webhook URL은 앱 설정에서 하나만 지정 가능하다. PR 단위로 다른 URL을 보내는 기능이 없다. 따라서 모든 webhook 이벤트는 Production Worker(github.dalestudy.com)로 먼저 도착한다.
Production Worker와 Staging Worker는 서로 다른 URL을 가진 완전히 독립된 서버 인스턴스이다 (코드, Secrets, 메모리 모두 별개). Staging Worker는 GitHub이 존재를 모르기 때문에 직접 webhook을 받을 수 없다.
그래서 Production Worker가 staging 라벨을 감지하면 fetch("https://github-staging.xxx/webhooks", ...)로 Staging Worker에 HTTP 요청을 보내는 방식으로 중계한다. 코드 내부 분기가 아니라, 서버 A → 서버 B로의 네트워크 통신이다.
이 방식을 선택한 이유
- 별도 레포 불필요: leetcode-study 안에서 라벨 하나로 구분
- 프로덕션 변경 최소화: 라우팅 로직은 단순 forward 분기 하나
- 완전 분리된 워커: Cloudflare Workers environments로 Production/Staging이 독립 인스턴스로 배포됨
- 리얼한 테스트: 실제 GitHub webhook 이벤트를 그대로 받아서 처리
구현 스펙
1. Cloudflare Workers 환경 분리
wrangler.jsonc에 staging 환경 추가:
wrangler deploy # → Production Worker
wrangler deploy --env staging # → Staging Worker (별도 인스턴스)
2. 스테이징 배포: GitHub Actions (workflow_dispatch)
스테이징 배포는 자동이 아닌 수동 트리거로 원하는 브랜치를 선택해서 배포한다.
name: Deploy Staging 🚀
on:
workflow_dispatch:
inputs:
branch:
description: "배포할 브랜치"
required: true
type: string
jobs:
deploy-staging:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.branch }}
- run: npx wrangler deploy --env staging
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
수동 트리거를 선택한 이유:
- 스테이징은 항상 돌릴 필요 없이 테스트할 때만 배포하면 됨
- 어떤 브랜치를 배포할지 명시적으로 제어 가능
- 이미
management.yaml에서 workflow_dispatch 패턴을 쓰고 있어서 팀에 익숙
3. Production Worker에 라우팅 로직 추가
/webhooks 핸들러 최상단에 staging 라벨 감지 및 포워딩:
const labels = payload.pull_request?.labels?.map(l => l.name) || [];
if (labels.includes("staging")) {
return fetch(env.STAGING_WORKER_URL + "/webhooks", request);
}
STAGING_WORKER_URL은 환경변수로 관리
- 포워딩 실패 시에도 프로덕션 처리에 영향 없음
4. Secrets 설정
Staging Worker Secrets (3개)
Cloudflare Workers secrets는 write-only로, 기존 Production 값을 조회/복제할 수 없다. Org owner 또는 Worker owner에게 아래 3개 값을 확인해야 한다:
| Secret |
확인 방법 |
비고 |
APP_ID |
GitHub App 설정 페이지에서 확인 (숫자) |
비밀 정보 아님 |
PRIVATE_KEY |
원본 PEM 파일 필요. 없으면 GitHub App 설정에서 새 키 발급 가능 |
새 키 발급 시 기존 키와 별개로 추가됨 |
OPENAI_API_KEY |
OpenAI 대시보드에서 확인 또는 새 키 발급 |
|
npx wrangler secret put APP_ID --env staging
npx wrangler secret put PRIVATE_KEY --env staging
npx wrangler secret put OPENAI_API_KEY --env staging
WEBHOOK_SECRET은 불필요
Production Worker가 GitHub 서명을 검증한 후에 Staging으로 포워딩하므로, Staging에서 다시 검증할 필요가 없다. 코드에서 env.WEBHOOK_SECRET 미설정 시 검증을 자동 스킵한다:
GitHub ─── X-Hub-Signature-256 ───► Production Worker ─── forward ───► Staging Worker
✅ 검증 완료 검증 스킵
(env.WEBHOOK_SECRET) (WEBHOOK_SECRET 미설정)
Production Worker 환경변수 (1개)
Staging Worker 배포 후 URL을 확인하여 Production에 설정:
npx wrangler secret put STAGING_WORKER_URL
# 입력: https://github-staging.daleseo.workers.dev
GitHub Actions Secret (1개)
GitHub repo Settings > Secrets > Actions에서 설정:
CLOUDFLARE_API_TOKEN: Cloudflare API Token (Workers 배포 권한)
5. 테스트 워크플로우
- 이 레포에서 기능 브랜치 작성
- GitHub Actions에서 해당 브랜치를 선택하여 스테이징 배포 실행
- leetcode-study에서 테스트 PR 생성,
staging 라벨 부착
- Staging Worker가 처리 → 테스트 PR에서 동작 확인
- 확인 완료 → 기능 브랜치를 main에 병합 → 운영 자동 배포
- 테스트 PR은 close
6. 고려사항
projects_v2_item 이벤트는 payload에 PR 라벨 정보가 직접 포함되지 않으므로 항상 Production에서 처리됨
issue_comment, pull_request_review_comment 이벤트는 payload.issue.labels 또는 payload.pull_request.labels로 라벨 확인 가능
- Staging Worker의 댓글/리뷰가 테스트 PR에 실제로 달리므로, 스터디 참여자에게 혼동이 없도록 staging 라벨의 용도를 팀에 공유
기대 효과
- 운영 환경 장애 예방 (revert 횟수 감소)
- PR 리뷰 시 실제 webhook 동작을 스테이징에서 확인 가능
- 개발 속도 향상 (빠른 피드백 루프)
배경
현재 개발 프로세스에서 새로운 기능이나 변경사항을 운영 배포 전에 검증할 방법이 없습니다.
현재 흐름:
운영 환경에 배포된 후에야 webhook 동작을 확인할 수 있어서, 문제가 발생하면 실제 스터디 참여자에게 영향을 미칩니다. 최근 3개의 PR이 연속 리버트된 이력(#17, #18, #19)이 이를 잘 보여줍니다.
원하는 흐름:
제약 조건
선택한 접근 방식
라벨 기반 스테이징 라우팅
leetcode-study 레포에서 테스트용 PR을 생성할 때
staging라벨을 붙이면, 프로덕션 워커가 해당 이벤트를 스테이징 워커로 포워딩한다.이 방식을 선택한 이유
구현 스펙
1. Cloudflare Workers 환경 분리
wrangler.jsonc에 staging 환경 추가:{ "name": "github", "main": "index.js", // ... "env": { "staging": { "name": "github-staging" } } }2. 스테이징 배포: GitHub Actions (workflow_dispatch)
스테이징 배포는 자동이 아닌 수동 트리거로 원하는 브랜치를 선택해서 배포한다.
수동 트리거를 선택한 이유:
management.yaml에서workflow_dispatch패턴을 쓰고 있어서 팀에 익숙3. Production Worker에 라우팅 로직 추가
/webhooks핸들러 최상단에 staging 라벨 감지 및 포워딩:STAGING_WORKER_URL은 환경변수로 관리4. Secrets 설정
Staging Worker Secrets (3개)
Cloudflare Workers secrets는 write-only로, 기존 Production 값을 조회/복제할 수 없다. Org owner 또는 Worker owner에게 아래 3개 값을 확인해야 한다:
APP_IDPRIVATE_KEYOPENAI_API_KEYWEBHOOK_SECRET은 불필요
Production Worker가 GitHub 서명을 검증한 후에 Staging으로 포워딩하므로, Staging에서 다시 검증할 필요가 없다. 코드에서
env.WEBHOOK_SECRET미설정 시 검증을 자동 스킵한다:Production Worker 환경변수 (1개)
Staging Worker 배포 후 URL을 확인하여 Production에 설정:
npx wrangler secret put STAGING_WORKER_URL # 입력: https://github-staging.daleseo.workers.devGitHub Actions Secret (1개)
GitHub repo Settings > Secrets > Actions에서 설정:
CLOUDFLARE_API_TOKEN: Cloudflare API Token (Workers 배포 권한)5. 테스트 워크플로우
staging라벨 부착6. 고려사항
projects_v2_item이벤트는 payload에 PR 라벨 정보가 직접 포함되지 않으므로 항상 Production에서 처리됨issue_comment,pull_request_review_comment이벤트는payload.issue.labels또는payload.pull_request.labels로 라벨 확인 가능기대 효과