Files
rtgs/sim/s2_failover.sh
rtgs 58ca23b5d9 Initialize RTGS prototype repository
3센터 A-A-A RTGS 실시간총액결제 프로토타입 최초 버전관리 시작.
- backend: Kotlin/Gradle 멀티모듈(sequencer, common, 채널/센터 모듈)
- frontend: Vite + TS
- infra: docker-compose, prometheus/grafana, ELK 네이티브 스크립트
- loadtest(k6), sim(장애/순서/정합성 시나리오), docs(PoC 보고서/복원력방안)
2026-07-15 15:37:32 +09:00

53 lines
2.5 KiB
Bash

#!/usr/bin/env bash
# S2 — 무손실 승계(복원성 축): 부하 중 원장엔진(Hermes)을 강제 종료했다가 재기동해도
# 선저널(write-ahead)+Kafka 오프셋 재생으로 유실 0·전건 완결되는지 검증.
# 복원력방안 부록A S2 재현. 실행: bash sim/s2_failover.sh [건수]
# ⚠ Hermes를 죽였다 살리므로 수동 기능테스트와 겹치지 않을 때 실행 권장.
cd "$(dirname "$0")"; source ./lib.sh
N=${1:-40}
FAILED=0
BANKS=(1001 1002 1003 1004 1005 1006 1007 1010)
declare -a BMIS
hr; echo "S2 무손실 승계 검증 — 이체 ${N}건 투입 중 Hermes 강제 종료·재기동"; hr
TOTAL_BEFORE=$(q "SELECT sum(balance) FROM account")
echo " 이체 전 총액 = $TOTAL_BEFORE"
KILL_AT=$((N/3)); RESTARTED=0
for ((i=1;i<=N;i++)); do
fi=${BANKS[$((RANDOM % ${#BANKS[@]}))]}
ti=${BANKS[$((RANDOM % ${#BANKS[@]}))]}
while [ "$ti" = "$fi" ]; do ti=${BANKS[$((RANDOM % ${#BANKS[@]}))]}; done
bmi=$(mkbmi "$fi" "$i"); BMIS+=("$bmi")
submit "$fi" "$ti" "$(( (RANDOM % 300) + 1 ))" "$bmi"
if [ "$i" = "$KILL_AT" ] && [ "$RESTARTED" = "0" ]; then
HP=$(pid_of hermes)
echo " >> $i건째: Hermes(PID $HP) 강제 종료"
[ -n "$HP" ] && taskkill //F //PID "$HP" //T >/dev/null 2>&1
sleep 3
echo " >> Hermes 재기동"
start_svc "RTGS Hermes (S2 재기동)" hermes
RESTARTED=1
fi
sleep 0.2
done
echo " 투입 완료. Hermes 복귀·정산 드레인 대기(최대 90s)..."
wait_drain 90 && echo " 드레인 완료" || echo " (경고) 드레인 타임아웃 — 아래 잔류 확인"
# 투입한 BMI 전건이 종료상태(ACCC/RJCT)에 도달했는지 — 단일 쿼리(IN 리스트)로 확인
INLIST=$(printf "'%s'," "${BMIS[@]}"); INLIST=${INLIST%,}
TERM=$(q "SELECT count(*) FROM transfer WHERE bmi IN ($INLIST) AND status IN ('ACCC','RJCT')")
STUCK_LIST=$(PSQL -t -A -c "SELECT bmi||'('||status||')' FROM transfer WHERE bmi IN ($INLIST) AND status NOT IN ('ACCC','RJCT')" | tr '\n' ' ')
TOTAL_AFTER=$(q "SELECT sum(balance) FROM account")
NEG=$(q "SELECT count(*) FROM account WHERE balance < 0")
hr; echo "결과"; hr
[ "$TERM" = "$N" ] && pass "투입 $N건 전건 완결(ACCC/RJCT) — 유실 0" || fail "$((N-TERM))건 미완결:$STUCK_LIST"
[ "$TOTAL_AFTER" = "$TOTAL_BEFORE" ] && pass "총액 보존: $TOTAL_AFTER" || fail "총액 불일치: $TOTAL_BEFORE -> $TOTAL_AFTER"
[ "$NEG" = "0" ] && pass "잔액 음수 계좌 0" || fail "음수 계좌 $NEG"
hr
[ "$FAILED" = "0" ] && echo "S2 PASS ✅ (선저널+오프셋 재생으로 무손실 승계)" || echo "S2 FAIL ❌"
exit $FAILED