Kotlin Coroutine 학습 프로젝트. Spring Boot 위에 REST 엔드포인트로 코루틴 개념 하나하나를 직접 호출해보고 관찰하는 구조다.
./gradlew bootRun # http://localhost:8081| 엔드포인트 | 개념 |
|---|---|
POST /launch-vs-async |
launch(결과 없음, fire-and-forget) vs async(결과를 await로 받음) |
POST /dispatchers |
Dispatchers.Default/IO/커스텀 풀의 동시성 한도 차이 (동시에 30개 던져서 몇 개의 스레드가 쓰였는지 카운트) |
POST /structured-concurrency |
coroutineScope 안 자식 하나가 실패하면 형제도 취소되고 예외가 전파됨 |
POST /cancellation |
withTimeout + isActive를 체크하는 협조적 코드 vs 체크 안 하는 비협조적 코드 |
POST /shared-state |
보호 없는 카운터(race condition) vs Mutex vs AtomicInteger |
POST /context-elements |
CoroutineContext는 Dispatcher/Job/CoroutineName이 +로 조합된 것 |
| 엔드포인트 | 개념 |
|---|---|
GET /basic |
cold stream: collect할 때마다 처음부터 다시 실행됨 |
GET /operators |
filter/map/take 체이닝 |
GET /backpressure |
buffer()(모두 처리) vs conflate()(느린 소비자 앞에서 중간값 스킵) |
GET /flow-on |
flowOn은 업스트림만 지정한 디스패처에서 돌리고, 다운스트림(collect)은 원래 컨텍스트 유지 |
| 엔드포인트 | 개념 |
|---|---|
POST /supervisor-job |
SupervisorJob 아래에서는 자식 실패가 형제에게 전파 안 됨 (structured-concurrency와 대비) |
POST /exception-handler |
CoroutineExceptionHandler는 launch의 예외는 잡지만 async의 예외는 못 잡음 (await()에서 직접 try/catch 필요) |
POST /retry |
코루틴 기반 수동 재시도(지수 백오프) |
Blocking(플랫폼 스레드) vs Virtual Thread vs Coroutine을 같은 지연 시나리오로 비교하기 위한 엔드포인트. k6 성능 테스트 대상.
| 엔드포인트 | 방식 |
|---|---|
GET /blocking?delayMs=200 |
Thread.sleep(), Tomcat 플랫폼 스레드 그대로 점유 |
GET /virtual-thread?delayMs=200 |
가상 스레드에 위임 + CompletableFuture 반환으로 Tomcat 스레드는 즉시 반납 |
GET /coroutine?delayMs=200 |
suspend fun + delay(), 스레드 비블로킹 |
./gradlew test각 *ServiceTest.kt가 위 개념들의 실제 동작을 assert로 증명한다. runBlocking을 쓴다(가상 시간 기반 runTest는 실제 디스패처/스레드 동시성을 검증하는 이 프로젝트의 테스트 목적과 안 맞아서 제외 — 자세한 이유는 블로그 참고).
# 모니터링 스택 (Prometheus: 9091, Grafana: 3001, admin/admin)
docker compose -f docker/monitoring-compose.yml up -d
# k6 부하 테스트 - Tomcat 기본 스레드 풀(200)을 넘겨야 blocking의 큐잉이 드러난다
MODE=blocking DELAY_MS=200 TARGET_VUS=800 k6 run k6/comparison-bench.js
MODE=virtual-thread DELAY_MS=200 TARGET_VUS=800 k6 run k6/comparison-bench.js
MODE=coroutine DELAY_MS=200 TARGET_VUS=800 k6 run k6/comparison-bench.jsGrafana: http://localhost:3001 — 요청 처리량, 응답시간, JVM 활성 스레드 수(방식별 실제 스레드 사용량 비교의 핵심), 에러율 패널 제공.