Skip to content

chimaek/chaos-http

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

4 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

chaos-http

์ฝ”๋“œ ํ•œ ์ค„ ์ˆ˜์ • ์—†์ด ์™ธ๋ถ€ API ์žฅ์• ๋ฅผ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๋Š” ๊ฐœ๋ฐœ์ž์šฉ ์นด์˜ค์Šค ํ”„๋ก์‹œ

CI License: MIT Java Spring Boot Docker PRs Welcome

๋น ๋ฅธ ์‹œ์ž‘ ยท ํ•ต์‹ฌ ๊ธฐ๋Šฅ ยท ์‹œ๋‚˜๋ฆฌ์˜ค ์˜ˆ์ œ ยท REST API ยท ๋ฌธ์„œ ยท ๊ธฐ์—ฌํ•˜๊ธฐ


์™œ chaos-http์ธ๊ฐ€?

๊ฐœ๋ฐœ ์ค‘ ๊ฐ€์žฅ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ค์šด ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” "์™ธ๋ถ€ API๊ฐ€ ์ฃฝ์—ˆ์„ ๋•Œ ๋‚ด ์„œ๋น„์Šค๋Š” ์–ด๋–ป๊ฒŒ ๋ฐ˜์‘ํ•˜๋Š”๊ฐ€" ์ž…๋‹ˆ๋‹ค.

๊ธฐ์กด ๋ฐฉ๋ฒ• ๋ฌธ์ œ์ 
Thread.sleep() ์‚ฝ์ž… ํ…Œ์ŠคํŠธ ํ›„ ๋ฐ˜๋“œ์‹œ ๋กค๋ฐฑ. ์‹ค์ˆ˜๋กœ ๋ฐฐํฌ๋  ์œ„ํ—˜
WireMock JSON/XML ์„ค์ • ์ž‘์„ฑ ํ•„์š”. ํ•™์Šต ๋น„์šฉ ๋†’์Œ
Toxiproxy TCP ๋ ˆ๋ฒจ๋งŒ ๊ฐ€๋Šฅ. HTTP ํ—ค๋”/๋ฐ”๋”” ๋ณ€์กฐ ๋ถˆ๊ฐ€. Web UI ์—†์Œ
์™ธ๋ถ€ API ๊ฐ•์ œ ์ข…๋ฃŒ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ํŒ€์›์—๊ฒŒ ์˜ํ–ฅ

chaos-http๋Š” ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ๋กœ ๋™์ž‘ํ•˜๋ฉฐ, ์›น ๋Œ€์‹œ๋ณด๋“œ์—์„œ ์ง€์—ฐ/์—๋Ÿฌ/ํƒ€์ž„์•„์›ƒ์„ ์‹ค์‹œ๊ฐ„ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ๋Š” ํ•œ ์ค„๋„ ์ˆ˜์ •ํ•  ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค.

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  ๋‚ด ์„œ๋น„์Šค    โ”‚ โ”€โ”€> โ”‚  chaos-http   โ”‚ โ”€โ”€> โ”‚  ์™ธ๋ถ€ API        โ”‚
โ”‚              โ”‚     โ”‚  :18080       โ”‚     โ”‚  api.kakao.com   โ”‚
โ”‚  localhost   โ”‚ <โ”€โ”€ โ”‚  ์ง€์—ฐ/์—๋Ÿฌ ์ฃผ์ž… โ”‚ <โ”€โ”€ โ”‚                  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                           โ”‚
                     โ”Œโ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”
                     โ”‚ Dashboard โ”‚
                     โ”‚  :9090    โ”‚
                     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿš€ ๋น ๋ฅธ ์‹œ์ž‘

Docker (๊ถŒ์žฅ)

# ์นด์นด์˜ค API๋ฅผ ํƒ€๊ฒŸ์œผ๋กœ ์‹œ์ž‘
docker run -p 18080:18080 -p 9090:9090 \
  ghcr.io/chimaek/chaos-http:latest \
  --chaos.proxy.target-url=https://api.kakao.com

# ์•ฑ์—์„œ ํ˜ธ์ถœ ์ฃผ์†Œ๋งŒ ๋ณ€๊ฒฝ
# Before: https://api.kakao.com/v2/user/me
# After:  http://localhost:18080/v2/user/me

# ์›น ๋Œ€์‹œ๋ณด๋“œ
open http://localhost:9090

Docker Compose

# ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ํƒ€๊ฒŸ ์ง€์ •
CHAOS_TARGET_URL=https://api.tosspayments.com \
  docker compose -f docker/docker-compose.yml up

JAR ์ง์ ‘ ์‹คํ–‰

cd chaos-proxy
./gradlew bootJar
java -jar build/libs/chaos-proxy-0.0.1-SNAPSHOT.jar \
  --chaos.proxy.target-url=https://httpbin.org

์ฒซ ์žฅ์•  ์ฃผ์ž… (30์ดˆ ์•ˆ์—!)

# 1. GET /get ์š”์ฒญ์— 100% 503 ์—๋Ÿฌ ์ฃผ์ž…
curl -X POST http://localhost:18080/api/v1/rules \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "์ฒซ ๋ฒˆ์งธ ์žฅ์• ",
    "pathPattern": "/get",
    "method": "GET",
    "enabled": true,
    "error": { "rate": 1.0, "statusCode": 503, "body": "{\"error\": \"chaos!\"}" }
  }'

# 2. ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด ์š”์ฒญ โ†’ 503 ์—๋Ÿฌ ํ™•์ธ
curl http://localhost:18080/get

# 3. ๋Œ€์‹œ๋ณด๋“œ์—์„œ ํ† ๊ธ€ OFF
open http://localhost:9090

โœจ ํ•ต์‹ฌ ๊ธฐ๋Šฅ

์ง€์—ฐ ์ฃผ์ž…

# 3์ดˆ ๊ณ ์ • ์ง€์—ฐ
curl -X POST http://localhost:18080/api/v1/rules \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "๋А๋ฆฐ API",
    "pathPattern": "/v2/user/**",
    "method": "GET",
    "latency": { "fixedMs": 3000 }
  }'

์—๋Ÿฌ ์ฃผ์ž…

# 30% ํ™•๋ฅ ๋กœ 500 ์—๋Ÿฌ
curl -X POST http://localhost:18080/api/v1/rules \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "๊ฐ„ํ—์  ์‹คํŒจ",
    "pathPattern": "/api/**",
    "error": { "rate": 0.3, "statusCode": 500, "body": "{\"error\": \"chaos injected\"}" }
  }'

ํƒ€์ž„์•„์›ƒ ์‹œ๋ฎฌ๋ ˆ์ด์…˜

# 5์ดˆ ํ›„ ์—ฐ๊ฒฐ ๊ฐ•์ œ ์ข…๋ฃŒ
curl -X POST http://localhost:18080/api/v1/rules \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "ํƒ€์ž„์•„์›ƒ",
    "pathPattern": "/v1/payments/confirm",
    "method": "POST",
    "timeout": { "afterMs": 5000 }
  }'

YAML ์‹œ๋‚˜๋ฆฌ์˜ค

๋ฏธ๋ฆฌ ์ •์˜๋œ ์‹œ๋‚˜๋ฆฌ์˜ค ํŒŒ์ผ๋กœ ํ•œ ๋ฒˆ์— ์—ฌ๋Ÿฌ ๋ฃฐ์„ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

# ๋ฒˆ๋“ค๋œ ์˜ˆ์ œ ์‹œ๋‚˜๋ฆฌ์˜ค ๋กœ๋“œ
curl -X POST http://localhost:18080/api/v1/scenarios/load \
  -H 'Content-Type: application/json' \
  -d '{"filename": "toss-payments.yml"}'

์‹ค์‹œ๊ฐ„ ๋Œ€์‹œ๋ณด๋“œ & SSE ๋กœ๊ทธ ์ŠคํŠธ๋ฆผ

# ์‹ค์‹œ๊ฐ„ ์š”์ฒญ ๋กœ๊ทธ ์ŠคํŠธ๋ฆผ (Server-Sent Events)
curl -N http://localhost:18080/api/v1/logs/stream

# ๋ฃฐ ๋ณ€๊ฒฝ ์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ
curl -N http://localhost:18080/api/v1/rules/stream

๋ฃฐ ํ† ๊ธ€

# ๋Œ€์‹œ๋ณด๋“œ์—์„œ ์›ํด๋ฆญ ๋˜๋Š” API๋กœ ON/OFF
curl -X PATCH http://localhost:18080/api/v1/rules/{id}/toggle

๐Ÿ“‹ ์‹œ๋‚˜๋ฆฌ์˜ค ์˜ˆ์ œ

scenarios/ ๋””๋ ‰ํ† ๋ฆฌ์— ๋ฐ”๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์˜ˆ์ œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

httpbin-demo.yml โ€” ๊ธฐ๋ณธ ๋ฐ๋ชจ

๋ฃฐ ์„ค๋ช…
demo-latency GET /get ์š”์ฒญ 3์ดˆ ์ง€์—ฐ
demo-error POST /post ์š”์ฒญ 50% 500 ์—๋Ÿฌ
demo-timeout /delay/** 5์ดˆ ํƒ€์ž„์•„์›ƒ

toss-payments.yml โ€” ํ† ์ŠคํŽ˜์ด๋จผ์ธ  ์žฅ์• 

๋ฃฐ ์„ค๋ช…
toss-payment-timeout ๊ฒฐ์ œ ์Šน์ธ 30์ดˆ ํƒ€์ž„์•„์›ƒ
toss-payment-error ๊ฒฐ์ œ API 10% ์‹คํŒจ
toss-webhook-delay ์›นํ›… 2~8์ดˆ ๋žœ๋ค ์ง€์—ฐ
toss-card-timeout ์นด๋“œ์‚ฌ ์‘๋‹ต 5์ดˆ ์ง€์—ฐ

kakao-api.yml โ€” ์นด์นด์˜ค API ์žฅ์• 

๋ฃฐ ์„ค๋ช…
kakao-profile-latency ํ”„๋กœํ•„ ์กฐํšŒ 3์ดˆ ์ง€์—ฐ
kakao-login-error ํ† ํฐ ๋ฐœ๊ธ‰ 30% ์‹คํŒจ
kakao-total-outage ์ „์ฒด API 503 ์žฅ์• 

๋ชจ๋“  ์‹œ๋‚˜๋ฆฌ์˜ค์˜ ๋ฃฐ์€ ๊ธฐ๋ณธ enabled: false์ž…๋‹ˆ๋‹ค. ๋Œ€์‹œ๋ณด๋“œ๋‚˜ API๋กœ ์›ํ•˜๋Š” ๋ฃฐ๋งŒ ํ™œ์„ฑํ™”ํ•˜์„ธ์š”.


๐Ÿ“ก REST API

๋ฉ”์„œ๋“œ ์—”๋“œํฌ์ธํŠธ ์„ค๋ช…
GET /api/v1/rules ์ „์ฒด ๋ฃฐ ๋ชฉ๋ก
POST /api/v1/rules ๋ฃฐ ์ƒ์„ฑ
GET /api/v1/rules/{id} ๋ฃฐ ์ƒ์„ธ ์กฐํšŒ
PUT /api/v1/rules/{id} ๋ฃฐ ์ˆ˜์ •
DELETE /api/v1/rules/{id} ๋ฃฐ ์‚ญ์ œ
PATCH /api/v1/rules/{id}/toggle ๋ฃฐ ON/OFF ํ† ๊ธ€
GET /api/v1/rules/stream ๋ฃฐ ๋ณ€๊ฒฝ SSE ์ŠคํŠธ๋ฆผ
GET /api/v1/logs ์š”์ฒญ ๋กœ๊ทธ ๋ชฉ๋ก
GET /api/v1/logs/stream ์‹ค์‹œ๊ฐ„ ๋กœ๊ทธ SSE ์ŠคํŠธ๋ฆผ
GET /api/v1/scenarios ์‹œ๋‚˜๋ฆฌ์˜ค ํŒŒ์ผ ๋ชฉ๋ก
POST /api/v1/scenarios/load ์‹œ๋‚˜๋ฆฌ์˜ค ๋กœ๋“œ
POST /api/v1/scenarios/save ์‹œ๋‚˜๋ฆฌ์˜ค ์ €์žฅ
GET /api/v1/config ๋Ÿฐํƒ€์ž„ ์„ค์ • ์กฐํšŒ
GET /api/v1/health ์ƒํƒœ ํ™•์ธ

์ „์ฒด API ๋ช…์„ธ: docs/API.md


๊ฒฝ์Ÿ ๋„๊ตฌ ๋น„๊ต

๊ธฐ๋Šฅ Toxiproxy WireMock Chaos Monkey chaos-http
Web UI ๋Œ€์‹œ๋ณด๋“œ - - - O
HTTP ํ—ค๋”/๋ฐ”๋”” ๋ณ€์กฐ - (TCP) O - O
๊ฒฝ๋กœ ๊ธฐ๋ฐ˜ ๋ฃฐ - O - O
YAML ์‹œ๋‚˜๋ฆฌ์˜ค ๊ณต์œ  - JSON - O
์‹ค์‹œ๊ฐ„ ON/OFF ํ† ๊ธ€ API๋งŒ - API๋งŒ UI+API
์ฝ”๋“œ ๋ณ€๊ฒฝ ํ•„์š” - ์„ค์ • O -

ํ•ต์‹ฌ ์ฐจ๋ณ„์ : Toxiproxy์˜ "ํ”„๋ก์‹œ ๋ฐฉ์‹(์ฝ”๋“œ ๋ฌด์ˆ˜์ •)"๊ณผ WireMock์˜ "HTTP ๋ ˆ๋ฒจ ์ œ์–ด"๋ฅผ ๊ฒฐํ•ฉํ•˜๊ณ , ์‹ค์‹œ๊ฐ„ Web UI๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.


์•„ํ‚คํ…์ฒ˜

์š”์ฒญ โ†’ RuleEngine(๋ฃฐ ๋งค์นญ) โ†’ LatencyFilter(์ง€์—ฐ) โ†’ ErrorFilter(์—๋Ÿฌ)
     โ†’ ProxyForward(ํƒ€๊ฒŸ ํฌ์›Œ๋”ฉ) โ†’ ResponseModify(์‘๋‹ต ๋ณ€์กฐ) โ†’ ์‘๋‹ต
์ปดํฌ๋„ŒํŠธ ์—ญํ• 
ProxyHandler ํ”„๋ก์‹œ ํŒŒ์ดํ”„๋ผ์ธ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜
RuleEngine ๊ฒฝ๋กœ+๋ฉ”์„œ๋“œ ๊ธฐ๋ฐ˜ ๋ฃฐ ๋งค์นญ (Ant-style)
RuleStore ์ธ๋ฉ”๋ชจ๋ฆฌ ๋ฃฐ ์ €์žฅ์†Œ (ConcurrentHashMap)
ScenarioLoader YAML ์‹œ๋‚˜๋ฆฌ์˜ค ๋กœ๋“œ/์ €์žฅ
RequestLogStore ์š”์ฒญ ๋กœ๊ทธ ๋ง ๋ฒ„ํผ + SSE ์ŠคํŠธ๋ฆผ
RuleEventPublisher ๋ฃฐ ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ SSE ๋ฉ€ํ‹ฐ์บ์ŠคํŠธ

์ƒ์„ธ ์•„ํ‚คํ…์ฒ˜: docs/ARCHITECTURE.md


๊ธฐ์ˆ  ์Šคํƒ

์˜์—ญ ๊ธฐ์ˆ 
๋Ÿฐํƒ€์ž„ Java 25 (Virtual Threads)
๋ฐฑ์—”๋“œ Spring Boot 4.0 + WebFlux + Reactor Netty
ํ”„๋ก ํŠธ์—”๋“œ React 19 + TypeScript + Vite
์‹ค์‹œ๊ฐ„ ํ†ต์‹  SSE (Server-Sent Events)
๋นŒ๋“œ Gradle 8.x
ํ…Œ์ŠคํŠธ JUnit 5 + WireMock + AssertJ
์ปจํ…Œ์ด๋„ˆ Docker (eclipse-temurin:25-jre-alpine)
AI (์„ ํƒ) Spring AI 2.0 (Anthropic, OpenAI, Ollama)

ํฌํŠธ

ํฌํŠธ ์šฉ๋„
18080 ํ”„๋ก์‹œ (์•ฑ์ด ์ด ํฌํŠธ๋กœ ์š”์ฒญ)
9090 ์›น ๋Œ€์‹œ๋ณด๋“œ
9091 Spring Actuator (Health, Metrics)

๊ฐœ๋ฐœ

# ๋นŒ๋“œ
cd chaos-proxy && ./gradlew build

# ๊ฐœ๋ฐœ ์„œ๋ฒ„ ์‹คํ–‰
./gradlew bootRun --args='--chaos.proxy.target-url=https://httpbin.org'

# ํ…Œ์ŠคํŠธ๋งŒ ์‹คํ–‰
./gradlew test

๊ฐœ๋ฐœ ๊ฐ€์ด๋“œ: docs/DEVELOPMENT.md


๐Ÿ“– ๋ฌธ์„œ

๋ฌธ์„œ ๋‚ด์šฉ
ARCHITECTURE.md ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜, ๋ฐ์ดํ„ฐ ํ๋ฆ„
API.md REST API ์ „์ฒด ๋ช…์„ธ + cURL ์˜ˆ์‹œ
DEVELOPMENT.md ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ •, ์ฝ”๋“œ ์˜ˆ์‹œ
AI_INTEGRATION.md AI ํ”„๋กœ๋ฐ”์ด๋” ์„ค์ • (์„ ํƒ์ )
ROADMAP.md ๊ฐœ๋ฐœ ๋กœ๋“œ๋งต

๐Ÿค ๊ธฐ์—ฌํ•˜๊ธฐ

๊ธฐ์—ฌ๋ฅผ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค! CONTRIBUTING.md๋ฅผ ์ฝ๊ณ  ์‹œ์ž‘ํ•˜์„ธ์š”.

ํ˜„์žฌ ๊ฐ€์žฅ ๋„์›€์ด ํ•„์š”ํ•œ ๋ถ€๋ถ„:

  1. ์˜ˆ์ œ ์‹œ๋‚˜๋ฆฌ์˜ค ์ถ”๊ฐ€ โ€” ์‹ค๋ฌด ์™ธ๋ถ€ API ์žฅ์•  ์‹œ๋‚˜๋ฆฌ์˜ค
  2. ํ…Œ์ŠคํŠธ ์ž‘์„ฑ โ€” ์—ฃ์ง€ ์ผ€์ด์Šค, ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ
  3. ๋ฌธ์„œ ๋ฒˆ์—ญ โ€” ์˜์–ด README, API ๋ฌธ์„œ

๋ผ์ด์„ ์Šค

MIT License โ€” ์ž์œ ๋กญ๊ฒŒ ์‚ฌ์šฉ, ์ˆ˜์ •, ๋ฐฐํฌํ•˜์„ธ์š”.

About

๐Ÿ”ฅ Simulate external API failures locally โ€” latency, errors, timeouts โ€” without changing a single line of code. Web dashboard included.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Contributors