Skip to content

fix: 배포 헬스체크를 로그 기반 완료 신호 감지 방식으로 변경#196

Open
unam98 wants to merge 1 commit into
devfrom
fix/log-based-healthcheck
Open

fix: 배포 헬스체크를 로그 기반 완료 신호 감지 방식으로 변경#196
unam98 wants to merge 1 commit into
devfrom
fix/log-based-healthcheck

Conversation

@unam98

@unam98 unam98 commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

작업 배경

  • OTel agent 적용 후 부팅 시간이 3s→20~30s로 늘어나면서, 고정 타임아웃(15s+10x10s) 기반 헬스체크가 정상 배포도 "실패"로 오판하는 구조적 문제 발견

변경 사항

영역 내용
scripts/deploy.sh 고정 폴링 방식 제거, 프로세스 생존 여부(진짜 실패) + 로그 기반 완료 신호(Started ServerApplication) 감지 방식으로 교체

영향 범위

  • 진짜 크래시(프로세스 종료)는 즉시 감지, 정상 부팅 중이면 시간이 얼마나 걸리든 계속 대기 (임의의 초/횟수 추측 제거)
  • 5분 상한선은 여전히 존재하나, 이는 "정상 부팅 시간" 추측이 아니라 진짜 행(hang) 상황에 대한 안전장치로 성격이 다름
  • CI/CD 워크플로우(dev-cd.yml 등)는 변경 없음

Test Plan

  • bash -n scripts/deploy.sh 문법 검증
  • 머지 후 실제 재배포하여 헬스체크가 정확히 판정하는지 확인

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved deployment startup verification by waiting for the application to report that it has started.
    • Added detection and reporting for startup crashes and readiness timeouts.
    • Displays recent application logs when startup fails.
    • Performs a final health check after successful startup.

기존 방식(15초 대기 + 10회x10초 폴링)은 OTel agent 계측으로 부팅 시간이
늘어나면서(3s→20~30s) 정상 배포도 실패로 오판하는 문제가 있었음.

이제 프로세스 생존 여부로 진짜 실패(크래시)를 즉시 감지하고, 살아있는 동안은
Spring Boot가 실제로 찍는 완료 로그("Started ServerApplication")를 기다림.
임의의 타임아웃 추측 대신 실제 이벤트 기반 판단이라 부팅 시간 변동에 안전하고,
5분 상한선은 진짜 행(hang) 상황에 대한 안전장치로만 남김.
@unam98 unam98 self-assigned this Jul 21, 2026
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Deployment readiness

Layer / File(s) Summary
Log-driven startup and health verification
scripts/deploy.sh
Starts the Java application with nohup, waits up to 300 seconds for the startup log signal, detects crashes and timeouts, then performs one health endpoint request.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: alh0409

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 배포 헬스체크를 로그 기반 완료 신호 감지 방식으로 바꾼 핵심 변경을 정확히 요약합니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/log-based-healthcheck

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
scripts/deploy.sh (1)

33-41: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Unbounded log growth from switching to append mode.

LOG_FILE is now appended (>> "$LOG_FILE") instead of truncated, needed to track START_LINE for readiness detection. Over many deploys with no rotation, nohup.out will grow indefinitely (worse with OTel agent output) and can eventually fill disk on the instance.

Also, LOG_FILE re-hardcodes /home/ec2-user/app/nohup.out even though APP_DIR=/home/ec2-user/app is already defined and the script cds into it — consider LOG_FILE="$APP_DIR/nohup.out" for consistency.

♻️ Suggested tweaks
-LOG_FILE=/home/ec2-user/app/nohup.out
+LOG_FILE="$APP_DIR/nohup.out"
 START_LINE=$(wc -l < "$LOG_FILE" 2>/dev/null || echo 0)

Add basic rotation (e.g., via logrotate config for nohup.out, or truncate/archive it on each deploy once START_LINE bookkeeping is no longer needed for the previous run).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/deploy.sh` around lines 33 - 41, Update the deployment script’s
LOG_FILE to derive from APP_DIR instead of hard-coding the application path, and
add basic nohup.out rotation or archival before appending new output. Preserve
START_LINE-based readiness detection by rotating only when the previous run’s
log bookkeeping is no longer needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/deploy.sh`:
- Around line 75-77: Update the health-check curl invocation in the deployment
script to include an explicit request timeout, ensuring an unavailable or
unresponsive actuator endpoint cannot block indefinitely. Keep the existing
health response logging behavior and do not change deployment success gating.
- Around line 43-73: Reduce MAX_WAIT in the readiness loop to leave sufficient
time below the AppSpec hook’s 300-second timeout for the earlier shutdown delay,
health check, and cleanup diagnostics; use a margin such as 240–270 seconds
while preserving the existing timeout failure path and 5-minute overall
hang-protection intent.

---

Nitpick comments:
In `@scripts/deploy.sh`:
- Around line 33-41: Update the deployment script’s LOG_FILE to derive from
APP_DIR instead of hard-coding the application path, and add basic nohup.out
rotation or archival before appending new output. Preserve START_LINE-based
readiness detection by rotating only when the previous run’s log bookkeeping is
no longer needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 82ea5247-ff4d-497f-86fd-985aeee49e1a

📥 Commits

Reviewing files that changed from the base of the PR and between e845749 and c0da68e.

📒 Files selected for processing (1)
  • scripts/deploy.sh

Comment thread scripts/deploy.sh
Comment on lines +43 to +73
echo "> 앱 준비 신호 대기 중 (최대 300초, 프로세스 생존 여부로 실패 판단)"
MAX_WAIT=300
ELAPSED=0
READY=false

for i in {1..10}; do
RESPONSE=$(curl -s http://localhost:8080/actuator/health || true)
if echo "$RESPONSE" | grep -q '"status":"UP"'; then
echo "> 헬스체크 성공"
break
fi
echo "> 헬스체크 실패($i/10): $RESPONSE"
if [ $i -eq 10 ]; then
while [ $ELAPSED -lt $MAX_WAIT ]; do
if ! kill -0 $APP_PID 2>/dev/null; then
echo "> 프로세스가 예기치 않게 종료됨 (크래시)"
echo "> 최근 로그:"
tail -n 40 "$LOG_FILE"
echo "> 배포 실패"
exit 1
fi
sleep 10

if tail -n +"$((START_LINE + 1))" "$LOG_FILE" | grep -q "Started ServerApplication"; then
echo "> 앱 준비 완료 신호 감지 (${ELAPSED}초 소요)"
READY=true
break
fi

sleep 2
ELAPSED=$((ELAPSED + 2))
done

if [ "$READY" != "true" ]; then
echo "> ${MAX_WAIT}초 내에 준비 신호 없음 — 안전장치 발동"
echo "> 최근 로그:"
tail -n 40 "$LOG_FILE"
echo "> 배포 실패"
exit 1
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

MAX_WAIT=300 matches the AppSpec hook's own 300s timeout, leaving no margin.

appspec.yml runs this script with timeout: 300 for the whole AfterInstall hook. This script's own readiness loop can consume the full 300s (line 44), on top of the earlier sleep 5 (line 14) for killing the previous process and the subsequent health curl (line 75) and nginx start. If the app is slow enough to approach MAX_WAIT, CodeDeploy will kill the entire script via its outer timeout before — or right around when — this loop's own graceful timeout branch (lines 67-73) would fire, so the intended "print log tail, exit 1 cleanly" diagnostics may never actually run. The PR's stated intent to keep the "5-minute limit for hang situations" while leaving CI/CD unchanged means this exact overlap should be accounted for.

Reduce MAX_WAIT to leave real margin under the 300s hook budget (e.g., 240-270s) so the script's own failure path reliably completes before CodeDeploy's outer timeout intervenes.

🛡️ Suggested fix
-MAX_WAIT=300
+MAX_WAIT=240

As per PR objectives, the 5-minute (300s) limit is intentionally retained for hang protection, but this needs coordination with the AppSpec hook's own 300s budget rather than an exact 1:1 match.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
echo "> 앱 준비 신호 대기 중 (최대 300초, 프로세스 생존 여부로 실패 판단)"
MAX_WAIT=300
ELAPSED=0
READY=false
for i in {1..10}; do
RESPONSE=$(curl -s http://localhost:8080/actuator/health || true)
if echo "$RESPONSE" | grep -q '"status":"UP"'; then
echo "> 헬스체크 성공"
break
fi
echo "> 헬스체크 실패($i/10): $RESPONSE"
if [ $i -eq 10 ]; then
while [ $ELAPSED -lt $MAX_WAIT ]; do
if ! kill -0 $APP_PID 2>/dev/null; then
echo "> 프로세스가 예기치 않게 종료됨 (크래시)"
echo "> 최근 로그:"
tail -n 40 "$LOG_FILE"
echo "> 배포 실패"
exit 1
fi
sleep 10
if tail -n +"$((START_LINE + 1))" "$LOG_FILE" | grep -q "Started ServerApplication"; then
echo "> 앱 준비 완료 신호 감지 (${ELAPSED}초 소요)"
READY=true
break
fi
sleep 2
ELAPSED=$((ELAPSED + 2))
done
if [ "$READY" != "true" ]; then
echo "> ${MAX_WAIT}초 내에 준비 신호 없음 — 안전장치 발동"
echo "> 최근 로그:"
tail -n 40 "$LOG_FILE"
echo "> 배포 실패"
exit 1
fi
echo "> 앱 준비 신호 대기 중 (최대 300초, 프로세스 생존 여부로 실패 판단)"
MAX_WAIT=240
ELAPSED=0
READY=false
while [ $ELAPSED -lt $MAX_WAIT ]; do
if ! kill -0 $APP_PID 2>/dev/null; then
echo "> 프로세스가 예기치 않게 종료됨 (크래시)"
echo "> 최근 로그:"
tail -n 40 "$LOG_FILE"
echo "> 배포 실패"
exit 1
fi
if tail -n +"$((START_LINE + 1))" "$LOG_FILE" | grep -q "Started ServerApplication"; then
echo "> 앱 준비 완료 신호 감지 (${ELAPSED}초 소요)"
READY=true
break
fi
sleep 2
ELAPSED=$((ELAPSED + 2))
done
if [ "$READY" != "true" ]; then
echo "> ${MAX_WAIT}초 내에 준비 신호 없음 — 안전장치 발동"
echo "> 최근 로그:"
tail -n 40 "$LOG_FILE"
echo "> 배포 실패"
exit 1
fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/deploy.sh` around lines 43 - 73, Reduce MAX_WAIT in the readiness
loop to leave sufficient time below the AppSpec hook’s 300-second timeout for
the earlier shutdown delay, health check, and cleanup diagnostics; use a margin
such as 240–270 seconds while preserving the existing timeout failure path and
5-minute overall hang-protection intent.

Comment thread scripts/deploy.sh
Comment on lines +75 to +77
RESPONSE=$(curl -s http://localhost:8080/actuator/health || true)
echo "> 헬스체크 확인: $RESPONSE"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Health curl has no timeout and its result doesn't gate success.

curl -s http://localhost:8080/actuator/health || true can hang indefinitely if the port isn't accepting connections yet, further eating into the already-tight 300s hook budget (see readiness-loop comment above). It also never fails the deploy even if the response is empty or reports DOWN, since only the raw string is echoed.

Add a request timeout so this can't block indefinitely, regardless of whether you decide to gate success on the response.

🛡️ Suggested fix
-RESPONSE=$(curl -s http://localhost:8080/actuator/health || true)
+RESPONSE=$(curl -s --max-time 10 http://localhost:8080/actuator/health || true)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
RESPONSE=$(curl -s http://localhost:8080/actuator/health || true)
echo "> 헬스체크 확인: $RESPONSE"
RESPONSE=$(curl -s --max-time 10 http://localhost:8080/actuator/health || true)
echo "> 헬스체크 확인: $RESPONSE"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/deploy.sh` around lines 75 - 77, Update the health-check curl
invocation in the deployment script to include an explicit request timeout,
ensuring an unavailable or unresponsive actuator endpoint cannot block
indefinitely. Keep the existing health response logging behavior and do not
change deployment success gating.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants