하트비트 모니터
하트비트 모니터는 방향을 뒤집습니다 - 작업이 살아 있다고 알려줍니다. 두 가지 모드: Scheduled(예상 주기)와 Event-Receiver(휴면; 트리거가 페이로드와 일치할 때만 발동).
모드
- Scheduled: 구성된 주기 내에 비트가 도착하지 않으면 상태가 MISS로 전환되고 알림이 발동합니다.
- Scheduled 명시적 실패: 작업은 실행되었지만 잘못된 결과가 감지되면 동일한 URL을 ?status=fail로 호출하세요. 이는 KO 비트를 기록하고 즉시 down 처리를 발동합니다.
- Event-Receiver: 상태가 휴면으로 유지됩니다. 각 비트는 페이로드를 저장하고, 조건이 있는 트리거가 이를 평가합니다. 트리거 조건이 무엇이 중요한지 결정하므로 Event-Receiver 모드에서는 ?status=fail이 무시됩니다.
OK beat:
curl -fsS https://keepitalive.dev/heartbeat/{token}
Explicit failed beat:
curl -fsS "https://keepitalive.dev/heartbeat/{token}?status=fail"SCHEDULED 레시피
*/5 * * * * curl -fsS https://keepitalive.dev/heartbeat/{token} >/dev/null0 2 * * * /usr/bin/backup.sh && curl -fsS https://keepitalive.dev/heartbeat/{token}curl -fsS "https://keepitalive.dev/heartbeat/{token}?status=fail&payload=disk+full"*/1 * * * * if ping -c 1 -W 2 192.168.1.50 >/dev/null 2>&1; then \
curl -fsS "https://keepitalive.dev/heartbeat/{token}"; \
else \
curl -fsS -X POST "https://keepitalive.dev/heartbeat/{token}?status=fail" \
-d "unreachable"; \
fi:: C:\scripts\keepalive_heartbeat.bat
@echo off
curl -fsS https://keepitalive.dev/heartbeat/{token} >nul 2>&1
:: schtasks /create /tn "KEEPitALIVE" /tr C:\scripts\keepalive_heartbeat.bat /sc minute /mo 5CRON 일정
일반 하트비트는 N초마다 신호를 기다리므로, 달력 기준으로 실행되는 작업에는 맞지 않습니다. 평일에만 도는 백업은 일요일마다 65시간 지연된 것처럼 보입니다. 대신 cron 표현식을 설정하면 기한이 “다음 예정 실행 + 유예 시간”이 됩니다. 무언가 예정되기 전에는 지연이 아닙니다. 작업이 실행되는 시간대를 선택하세요. 일정은 그 시간대에서 평가되며, 그래야 서머타임이 바뀌어도 03:00 작업이 03:00에 유지됩니다. 표현식은 비용도 결정합니다. 시간당 예상 실행 횟수를 정하기 때문입니다. 수집 URL은 그대로이며, 신호를 언제 기대하는지만 달라집니다.
# Give the monitor the same schedule the job runs on.
0 3 * * 1-5 # 03:00, weekdays only
*/15 * * * * # every 15 minutes
0 3 1 * * # 03:00 on the 1st of the month
@daily # midnight
# Pick the zone the job runs in, not the server's: that is
# what keeps 03:00 at 03:00 when the clocks change.종료 코드
작업의 종료 코드를 URL 뒤에 붙이면 비트가 스스로 결과를 보고합니다. 0은 성공, 그 외의 값은 실패입니다. && 로 연결하는 방식보다 낫습니다. && 는 작업이 실패하면 아무것도 보내지 않으므로, 고장난 순간이 아니라 나중에 구간을 놓쳤을 때에야 모니터가 다운됩니다. 코드는 비트에 저장되므로 트리거 조건에서 어떤 실패인지에 따라 분기할 수 있습니다. payload.exit_code == 137(메모리 부족으로 종료)은 장애를 열고, payload.exit_code == 1 은 알림만 보내도록 할 수 있습니다. 코드는 0-255 범위여야 하며, 코드가 없으면 /fail 을 사용해도 됩니다.
# $? is the exit status of the job that just ran
0 2 * * * /usr/bin/backup.sh; curl -fsS https://keepitalive.dev/heartbeat/{token}/$?
# Send the job output too, so the alert says why it failed.
# Capture it first: in a pipeline $? is the last command's status,
# not the job's.
0 2 * * * out=$(/usr/bin/backup.sh 2>&1); \
curl -fsS --data-binary "$out" https://keepitalive.dev/heartbeat/{token}/$?실행 시간
작업 시작 시 /start를 호출하고 종료 시 일반 신호를 보내면 경과 시간이 duration_ms로 신호에 저장되어, 느린 실행에 대해 알림을 보낼 수 있습니다. payload.duration_ms > 300000은 결국 성공했더라도 5분을 넘긴 백업을 잡아냅니다. /start는 완전히 선택 사항입니다. 종료 신호 하나만으로도 완전한 보고가 되며, 누락 감지와 종료 코드는 /start 없이도 작동합니다. /start를 보내면 정확히 두 가지를 얻습니다: 기록된 실행 시간, 그리고 끝나지 않는 실행의 감지. /start만으로는 아무것도 보고되지 않고 모니터 상태도 바뀌지 않습니다. 시작 후 멈춘 작업은 여전히 기한을 놓쳐야 하기 때문입니다. 실행이 열려 있는 동안 두 번째 /start는 거부됩니다. 종료 없이 두 번 시작했다는 것은 첫 실행이 보고하지 않았다는 뜻이기 때문입니다. 해당 실행이 기한을 넘기면 거부가 해제됩니다. 24시간 넘게 열려 있는 실행은 폐기됩니다.
# /start is optional. Without it you still get miss detection
# and the exit status - just no duration and no stuck-run alert:
0 2 * * * /usr/bin/backup.sh; curl -fsS https://keepitalive.dev/heartbeat/{token}/$?
# With it, the run is timed and a job that never finishes is caught:
0 2 * * * curl -fsS https://keepitalive.dev/heartbeat/{token}/start; \
/usr/bin/backup.sh; \
curl -fsS https://keepitalive.dev/heartbeat/{token}/$?멈춘 실행
작업이 /start 를 호출한 뒤 멈추면 아직 지연된 것은 없습니다. 시작은 아무것도 갱신하지 않으므로 다음 비트가 예정된 시각까지 모니터는 정상으로 보입니다. 바로 이 공백이 작업 시간을 재는 일의 핵심 문제입니다. 멈춘 실행이야말로 잡으려던 장애이기 때문입니다. 그래서 종료 비트를 보내지 않은 실행은 간격에 유예 시간을 더한 값을 넘기는 순간 다운으로 처리되며, 얼마나 오래 실행 중인지 오류에 표시됩니다. 별도의 최대 실행 시간 설정은 없습니다. 늦은 비트와 멈춘 실행은 결국 같은 질문, 즉 얼마나 기다릴 것인가이므로 이미 설정한 유예 값이 둘 다 답합니다.
페이로드
시스템 지표나 임의의 필드를 보고하려면 하트비트 URL로 JSON을 POST하세요. 모니터 상세 페이지의 최신 보고 카드는 가능한 경우 최신 페이로드를 보기 좋은 JSON으로 렌더링하며, 원시 텍스트로 폴백합니다.
curl -fsS -X POST https://keepitalive.dev/heartbeat/{token} \
-H 'Content-Type: application/json' \
-d '{"job":"nightly-backup","status":"ok","rows":42850}'EVENT RECEIVER: CI/CD 유지보수
Event Receiver 모드는 배포 파이프라인에 유용합니다. 조건 payload.status == "maintenance"와 인시던트 분류 maintenance로 페이로드 트리거를 만드세요. 배포 전에 maintenance 페이로드를 보내고, if: always() 최종 단계에서 running/ok 페이로드를 보내세요. 표현식이 일치하는 동안 인시던트가 열리고, 다음 수락 페이로드가 이를 해제하면 닫힙니다.
- name: Start maintenance
run: |
curl -fsS -X POST "$KEEPITALIVE_HEARTBEAT_URL" \
-H "Content-Type: application/json" \
-d '{"status":"maintenance","source":"github-actions","sha":"${{github.sha}}"}'
- name: Deploy
run: ./deploy.sh
- name: End maintenance
if: always()
run: |
curl -fsS -X POST "$KEEPITALIVE_HEARTBEAT_URL" \
-H "Content-Type: application/json" \
-d '{"status":"running","source":"github-actions","sha":"${{github.sha}}"}'이벤트 수신기는 수락된 페이로드를 모니터 주기로 조절합니다. 매우 짧은 배포 작업의 경우, 요금제가 허용하는 가장 작은 주기를 사용하거나 주기가 경과할 때까지 최종 페이로드를 지연하세요. 소스가 침묵하면 KEEPitALIVE는 복구를 가정하지 않습니다.
#!/bin/bash
URL="https://keepitalive.dev/heartbeat/{token}"
CPU=$(top -bn1 | grep "Cpu" | awk '{print $2}')
RAM=$(free -m | awk '/Mem/{printf "%.1f", $3/$2*100}')
DISK=$(df -h / | awk 'NR==2{print $5}')
curl -fsS -X POST $URL \
-H "Content-Type: application/json" \
-d "{\"hostname\":\"$(hostname)\",\"cpu\":\"$CPU%\",\"ram\":\"$RAM%\",\"disk\":\"$DISK\"}"$url = "https://keepitalive.dev/heartbeat/{token}"
$os = Get-CimInstance Win32_OperatingSystem
$body = @{
hostname = $env:COMPUTERNAME
cpu = "{0:N1}%" -f (Get-CimInstance Win32_Processor).LoadPercentage
ram = "{0:N1}%" -f ((1 - $os.FreePhysicalMemory / $os.TotalVisibleMemorySize) * 100)
} | ConvertTo-Json
Invoke-RestMethod -Uri $url -Method POST -Body $body -ContentType "application/json"