Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces Grafana dashboards for load testing and production monitoring, updates several k6 test scripts to support multi-token pools and fail-fast auth token checks, and adds a new Bash runner script (run.sh). Feedback on the changes highlights a critical issue in the circuit breaker script where an early return without a sleep can lead to 100% CPU utilization. Additionally, improvements were suggested to clean up duplicate token parsing logic in the coupon script, prevent word-splitting issues in run.sh using Bash arrays, and replace a regex comparison with standard wildcard matching for better Bash compatibility.
| // 안전 가드 — 이 VU가 MAX_ITER_PER_VU 도달 시 추가 호출 중단 (Gemini 비용 차단) | ||
| vuIterCount++; | ||
| if (MAX_ITER_PER_VU > 0 && vuIterCount > MAX_ITER_PER_VU) { | ||
| skippedSafeguard.add(1); | ||
| return; | ||
| } |
There was a problem hiding this comment.
MAX_ITER_PER_VU 도달 시 return을 통해 조기 반환하고 있으나, 반환하기 전에 sleep을 호출하지 않습니다. k6의 constant-vus 또는 ramping-vus 실행기는 테스트 기간 동안 default 함수를 루프 내에서 계속 실행하므로, sleep 없이 즉시 반환하게 되면 해당 VU는 아무런 대기 시간 없이 무한 루프를 돌게 됩니다.
이로 인해 k6 러너의 CPU 사용량이 100%로 치솟고, skipped_by_safeguard 메트릭이 순식간에 수백만 건 이상 생성되어 시스템 메모리 고갈이나 k6 프로세스 다운을 유발할 수 있습니다.
안전 가드가 작동한 후에는 CPU 과점유를 방지하기 위해 sleep을 호출한 후 반환하는 것이 안전합니다.
| // 안전 가드 — 이 VU가 MAX_ITER_PER_VU 도달 시 추가 호출 중단 (Gemini 비용 차단) | |
| vuIterCount++; | |
| if (MAX_ITER_PER_VU > 0 && vuIterCount > MAX_ITER_PER_VU) { | |
| skippedSafeguard.add(1); | |
| return; | |
| } | |
| // 안전 가드 — 이 VU가 MAX_ITER_PER_VU 도달 시 추가 호출 중단 (Gemini 비용 차단) | |
| vuIterCount++; | |
| if (MAX_ITER_PER_VU > 0 && vuIterCount > MAX_ITER_PER_VU) { | |
| skippedSafeguard.add(1); | |
| sleep(1); // CPU 100% 점유 및 메트릭 폭증 방지를 위해 sleep 추가 | |
| return; | |
| } |
| // 빈 AUTH_TOKEN + 빈 TOKENS 환경변수 → 즉시 fail-fast (사일런트 401 방지) | ||
| export function setup() { | ||
| const hasMulti = (__ENV.TOKENS || '').split(',').filter(Boolean).length > 1; | ||
| if (!AUTH_TOKEN && !hasMulti) { | ||
| requireAuthToken('08'); | ||
| } | ||
| } | ||
|
|
||
| // 발급할 쿠폰 템플릿 ID — run.ps1 -CouponTemplateId 로 주입 | ||
| const TEMPLATE_ID = __ENV.COUPON_TEMPLATE_ID || '1'; | ||
|
|
||
| // 다중 토큰 풀 (선택) — CSV 형식, 단일 토큰만 있으면 AUTH_TOKEN 사용 (검증 의미 반감) | ||
| const TOKENS = (__ENV.TOKENS ? __ENV.TOKENS.split(',') : []).filter(Boolean); | ||
| const USE_MULTI_TOKENS = TOKENS.length > 1; |
There was a problem hiding this comment.
setup() 함수 내부에서 __ENV.TOKENS를 파싱하여 hasMulti를 계산하는 로직이 모듈 레벨에서 정의된 USE_MULTI_TOKENS와 완전히 중복됩니다.
TOKENS와 USE_MULTI_TOKENS 선언부를 setup() 함수 위로 이동시키면, 중복 코드를 제거하고 setup() 내부에서 USE_MULTI_TOKENS를 직접 활용하여 코드를 더 깔끔하게 유지할 수 있습니다.
| // 빈 AUTH_TOKEN + 빈 TOKENS 환경변수 → 즉시 fail-fast (사일런트 401 방지) | |
| export function setup() { | |
| const hasMulti = (__ENV.TOKENS || '').split(',').filter(Boolean).length > 1; | |
| if (!AUTH_TOKEN && !hasMulti) { | |
| requireAuthToken('08'); | |
| } | |
| } | |
| // 발급할 쿠폰 템플릿 ID — run.ps1 -CouponTemplateId 로 주입 | |
| const TEMPLATE_ID = __ENV.COUPON_TEMPLATE_ID || '1'; | |
| // 다중 토큰 풀 (선택) — CSV 형식, 단일 토큰만 있으면 AUTH_TOKEN 사용 (검증 의미 반감) | |
| const TOKENS = (__ENV.TOKENS ? __ENV.TOKENS.split(',') : []).filter(Boolean); | |
| const USE_MULTI_TOKENS = TOKENS.length > 1; | |
| // 발급할 쿠폰 템플릿 ID — run.ps1 -CouponTemplateId 로 주입 | |
| const TEMPLATE_ID = __ENV.COUPON_TEMPLATE_ID || '1'; | |
| // 다중 토큰 풀 (선택) — CSV 형식, 단일 토큰만 있으면 AUTH_TOKEN 사용 (검증 의미 반감) | |
| const TOKENS = (__ENV.TOKENS ? __ENV.TOKENS.split(',') : []).filter(Boolean); | |
| const USE_MULTI_TOKENS = TOKENS.length > 1; | |
| // 빈 AUTH_TOKEN + 빈 TOKENS 환경변수 → 즉시 fail-fast (사일런트 401 방지) | |
| export function setup() { | |
| if (!AUTH_TOKEN && !USE_MULTI_TOKENS) { | |
| requireAuthToken('08'); | |
| } | |
| } |
| if [[ -n "$PROMETHEUS_URL" ]]; then | ||
| export K6_PROMETHEUS_RW_SERVER_URL="$PROMETHEUS_URL" | ||
| k6 run \ | ||
| --out "experimental-prometheus-rw" \ | ||
| -e "BASE_URL=$BASE_URL" \ | ||
| -e "AUTH_TOKEN=$AUTH_TOKEN" \ | ||
| -e "REMAIN_ID=$REMAIN_ID" \ | ||
| -e "COUPON_TEMPLATE_ID=$COUPON_TEMPLATE_ID" \ | ||
| ${TOKENS_ENV:+-e "TOKENS=$TOKENS_ENV"} \ | ||
| "$SCRIPT" | ||
| else | ||
| k6 run \ | ||
| -e "BASE_URL=$BASE_URL" \ | ||
| -e "AUTH_TOKEN=$AUTH_TOKEN" \ | ||
| -e "REMAIN_ID=$REMAIN_ID" \ | ||
| -e "COUPON_TEMPLATE_ID=$COUPON_TEMPLATE_ID" \ | ||
| ${TOKENS_ENV:+-e "TOKENS=$TOKENS_ENV"} \ | ||
| "$SCRIPT" | ||
| fi |
There was a problem hiding this comment.
${TOKENS_ENV:+-e "TOKENS=$TOKENS_ENV"}와 같이 큰따옴표 없이 환경 변수를 확장하면 Bash에서 단어 분할(Word Splitting)이 발생할 수 있어, 토큰 파일에 공백이나 개행이 포함되어 있을 경우 명령어가 오작동할 위험이 있습니다.
또한 PROMETHEUS_URL 유무에 따라 거의 동일한 k6 run 명령어 코드가 중복되어 작성되어 있습니다.
Bash 배열(Array)을 사용하여 공통 인자를 정의하고 조건부로 인자를 추가하는 방식을 사용하면, 단어 분할 위험을 완벽히 방지하면서 코드 중복도 깔끔하게 제거할 수 있습니다.
| if [[ -n "$PROMETHEUS_URL" ]]; then | |
| export K6_PROMETHEUS_RW_SERVER_URL="$PROMETHEUS_URL" | |
| k6 run \ | |
| --out "experimental-prometheus-rw" \ | |
| -e "BASE_URL=$BASE_URL" \ | |
| -e "AUTH_TOKEN=$AUTH_TOKEN" \ | |
| -e "REMAIN_ID=$REMAIN_ID" \ | |
| -e "COUPON_TEMPLATE_ID=$COUPON_TEMPLATE_ID" \ | |
| ${TOKENS_ENV:+-e "TOKENS=$TOKENS_ENV"} \ | |
| "$SCRIPT" | |
| else | |
| k6 run \ | |
| -e "BASE_URL=$BASE_URL" \ | |
| -e "AUTH_TOKEN=$AUTH_TOKEN" \ | |
| -e "REMAIN_ID=$REMAIN_ID" \ | |
| -e "COUPON_TEMPLATE_ID=$COUPON_TEMPLATE_ID" \ | |
| ${TOKENS_ENV:+-e "TOKENS=$TOKENS_ENV"} \ | |
| "$SCRIPT" | |
| fi | |
| K6_ARGS=( | |
| -e "BASE_URL=$BASE_URL" | |
| -e "AUTH_TOKEN=$AUTH_TOKEN" | |
| -e "REMAIN_ID=$REMAIN_ID" | |
| -e "COUPON_TEMPLATE_ID=$COUPON_TEMPLATE_ID" | |
| ) | |
| if [[ -n "${TOKENS_ENV:-}" ]]; then | |
| K6_ARGS+=(-e "TOKENS=$TOKENS_ENV") | |
| fi | |
| if [[ -n "$PROMETHEUS_URL" ]]; then | |
| export K6_PROMETHEUS_RW_SERVER_URL="$PROMETHEUS_URL" | |
| k6 run --out "experimental-prometheus-rw" "${K6_ARGS[@]}" "$SCRIPT" | |
| else | |
| k6 run "${K6_ARGS[@]}" "$SCRIPT" | |
| fi |
| esac | ||
|
|
||
| # ── prod 도메인 감지 시 경고 ──────────────────────────────────────────────── | ||
| if [[ "$BASE_URL" =~ catcheat\.kro\.kr|api\.catchtable ]]; then |
There was a problem hiding this comment.
[[ "$BASE_URL" =~ catcheat.kro.kr|api.catchtable ]]와 같은 정규식 비교 연산자(=~)는 Bash 버전에 따라(특히 macOS의 기본 Bash 3.2 등) 이스케이프 처리 방식이 달라 오작동할 가능성이 있습니다.
단순히 특정 도메인이 포함되어 있는지 확인하는 목적이라면, Bash의 표준 와일드카드 패턴 매칭(==)을 사용하는 것이 훨씬 안전하고 이식성이 높습니다.
| if [[ "$BASE_URL" =~ catcheat\.kro\.kr|api\.catchtable ]]; then | |
| if [[ "$BASE_URL" == *"catcheat.kro.kr"* || "$BASE_URL" == *"api.catchtable"* ]]; then |
📢 기능 설명
필요시 실행결과 스크린샷 첨부
연결된 issue
연결된 issue를 자동을 닫기 위해 아래 {이슈넘버}를 입력해주세요.
close #{이슈넘버}
✅ 체크리스트