- typescript: communicator nonce handling and WS client improvements - typescript: performance benchmark and test updates - agent-ops: update test matrix scripts for performance/stress - agent-roadmap: update milestone documentation - agent-task: add kotlin tcp parallel optimization task
193 lines
9.5 KiB
Markdown
193 lines
9.5 KiB
Markdown
<!-- task=m-large-payload-followup-optimization/03_kotlin_tcp_parallel plan=0 tag=PERF -->
|
|
|
|
# Kotlin TCP Parallel Required Skip Unblock Plan
|
|
|
|
## 이 파일을 읽는 구현 에이전트에게
|
|
|
|
이 plan의 구현 완료 조건에는 대응 `CODE_REVIEW-cloud-G07.md`의 구현 에이전트 소유 섹션 작성이 포함된다. 구현 후 검증 명령을 실행하고 실제 출력, 계획 대비 변경, 주요 설계 결정을 채운 뒤 active 파일을 그대로 둔 채 리뷰 준비를 보고한다. 사용자만 결정할 수 있는 범위 변경, 외부 환경/secret/서비스 준비, 또는 구현을 안전하게 계속할 수 없는 충돌이 있으면 review stub의 `사용자 리뷰 요청` 섹션에 정확한 근거를 기록하고 중단한다. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 재실행으로 닫을 수 있는 검증 증거 공백은 사용자 리뷰 요청이 아니다.
|
|
|
|
## 배경
|
|
|
|
현 마일스톤의 `[kotlin-tcp-parallel-unskip-path]`는 Kotlin TCP full parallel clients 128/512/1024 required SKIP을 해제하는 작업이다. 현재 skip 사유는 blocking read-thread-per-connection이 TCP parallel clients>=128에서 thread starvation/deadlock을 만든다는 것이다. skip을 제거하려면 read loop와 dispatcher 전략을 고치고, full parallel stress에서 required skip 0과 hard gate 0을 증명해야 한다.
|
|
|
|
## 사용자 리뷰 요청 흐름
|
|
|
|
구현 중 사용자 결정이 필요한 경우 active `CODE_REVIEW-cloud-G07.md`의 `사용자 리뷰 요청` 섹션에 `agent-ops/skills/common/_templates/implementation-user-review-request-section.md` 형식으로 기록한다. 구현 에이전트는 직접 사용자 프롬프트를 만들지 않으며, code-review가 해당 요청을 검증하고 실제 `USER_REVIEW.md` 작성 여부를 판단한다.
|
|
|
|
## Roadmap Targets
|
|
|
|
- Milestone: `agent-roadmap/milestones/large-payload-followup-optimization.md`
|
|
- Task ids:
|
|
- `kotlin-tcp-parallel-unskip-path`: Kotlin TCP parallel clients>=128 required skip 해제
|
|
- Completion mode: check-on-pass
|
|
|
|
## 분석 결과
|
|
|
|
### 읽은 파일
|
|
|
|
- `agent-ops/rules/project/rules.md`
|
|
- `agent-ops/rules/project/domain/kotlin/rules.md`
|
|
- `agent-ops/rules/common/rules-roadmap.md`
|
|
- `agent-roadmap/current.md`
|
|
- `agent-roadmap/milestones/large-payload-followup-optimization.md`
|
|
- `agent-ops/skills/common/router.md`
|
|
- `agent-ops/skills/common/plan/SKILL.md`
|
|
- `agent-test/local/rules.md`
|
|
- `agent-test/local/proto-socket-performance-baseline.md`
|
|
- `agent-test/runs/20260613-141506-proto-socket-performance-full.md`
|
|
- `agent-test/runs/20260613-141506-proto-socket-stress-full.md`
|
|
- `kotlin/src/main/kotlin/com/tokilabs/proto_socket/TcpClient.kt`
|
|
- `kotlin/src/main/kotlin/com/tokilabs/proto_socket/TcpServer.kt`
|
|
- `kotlin/src/main/kotlin/com/tokilabs/proto_socket/BaseClient.kt`
|
|
- `kotlin/src/main/kotlin/com/tokilabs/proto_socket/Communicator.kt`
|
|
- `kotlin/crosstest/stress.kt`
|
|
- `kotlin/src/test/kotlin/com/tokilabs/proto_socket/TcpTest.kt`
|
|
- `kotlin/build.gradle.kts`
|
|
|
|
### 테스트 환경 규칙
|
|
|
|
- `test_env=local`; `agent-test/local/rules.md` 및 `agent-test/local/proto-socket-performance-baseline.md`를 읽었다.
|
|
- 대상 task에 명시된 검증은 `run_stress.sh --full --lang kotlin --transport tcp --profile parallel`이며 required skip 0과 hard gate 0이 완료 조건이다.
|
|
- layout 확인: `kotlin/gradlew`, `run_stress.sh`, `bash`, `dart`/기타 toolchain 존재 확인 중 Kotlin target에는 `gradlew`와 JDK가 필요하다.
|
|
|
|
### 테스트 커버리지 공백
|
|
|
|
- `kotlin/src/test/kotlin/com/tokilabs/proto_socket/TcpTest.kt`는 소규모 concurrent request만 검증한다.
|
|
- clients>=128 thread starvation은 unit test로 신뢰성 있게 재현하기 어렵다. skip 제거와 full stress가 필수 검증이다.
|
|
|
|
### 심볼 참조
|
|
|
|
- renamed/removed symbol: none.
|
|
|
|
### 분할 판단
|
|
|
|
- shared task group: `agent-task/m-large-payload-followup-optimization/`.
|
|
- sibling split은 `01_typescript_ws_1mb`, `02_typescript_tcp_tail`, `03_kotlin_tcp_parallel`, `04_ws_fixed_latency`, `05_dart_large_packet_guard`이며 모두 독립이다.
|
|
- 본 작업은 Kotlin TCP runtime과 Kotlin stress skip 제거만 대상으로 하며 TypeScript TCP tail과 독립이다.
|
|
|
|
### 범위 결정 근거
|
|
|
|
- WebSocket, TLS, cross-language adapter, protobuf schema는 제외한다.
|
|
- stress clients/perClient matrix를 축소하거나 required skip을 optional로 바꾸는 방식은 완료로 인정하지 않는다.
|
|
|
|
### 빌드 등급
|
|
|
|
- `cloud-G07`: Kotlin coroutine dispatcher, blocking socket read, high-client stress가 얽힌 concurrency 작업이고 verification이 terminal benchmark에 의존한다.
|
|
|
|
## 구현 체크리스트
|
|
|
|
- [ ] [PERF-1] Kotlin TCP read loop가 Dispatchers.IO starvation을 만들지 않도록 bounded read timeout과 격리된 read execution 전략을 적용한다.
|
|
- [ ] [PERF-2] Kotlin stress의 TCP parallel required skip을 제거하고 clients=128/512/1024 row를 실제 측정한다.
|
|
- [ ] Kotlin TCP full parallel stress를 실행해 required skip 0, timeout/nonce/type/FIFO/pending leak 0을 확인한다.
|
|
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
|
|
|
|
### [PERF-1] TCP blocking read loop 격리
|
|
|
|
문제: `kotlin/src/main/kotlin/com/tokilabs/proto_socket/TcpClient.kt:70-97`은 connection마다 `Dispatchers.IO`에서 blocking `readInt/readFully`를 실행한다. clients>=128에서 read thread가 IO lane을 점유하면 write/accept/handler 진행이 막혀 full stress가 deadlock 후보가 된다.
|
|
|
|
해결 방법:
|
|
|
|
```kotlin
|
|
// before: kotlin/src/main/kotlin/com/tokilabs/proto_socket/TcpClient.kt:70
|
|
scope.launch(Dispatchers.IO) {
|
|
val input = DataInputStream(socket.getInputStream())
|
|
while (isAlive()) {
|
|
val length = input.readInt()
|
|
...
|
|
}
|
|
}
|
|
```
|
|
|
|
```kotlin
|
|
// after: shape
|
|
socket.soTimeout = TCP_READ_POLL_TIMEOUT_MS
|
|
scope.launch(tcpReadDispatcher) {
|
|
val input = DataInputStream(socket.getInputStream())
|
|
while (isAlive()) {
|
|
try {
|
|
val length = input.readInt()
|
|
...
|
|
} catch (_: SocketTimeoutException) {
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
- read dispatcher는 write/accept 작업과 starvation을 공유하지 않게 분리한다.
|
|
- `SocketTimeoutException`은 정상 poll로 처리하고, EOF/IOException은 기존 disconnect semantics를 유지한다.
|
|
- close 시 dispatcher/resource leak이 생기지 않도록 lifecycle 소유권을 명확히 한다.
|
|
|
|
수정 파일 및 체크리스트:
|
|
|
|
- [ ] `kotlin/src/main/kotlin/com/tokilabs/proto_socket/TcpClient.kt`: read timeout, read dispatcher, exception 분기 추가.
|
|
- [ ] `kotlin/src/main/kotlin/com/tokilabs/proto_socket/BaseClient.kt`: 필요 시 dispatcher close/lifecycle hook을 추가한다.
|
|
- [ ] `kotlin/src/test/kotlin/com/tokilabs/proto_socket/TcpTest.kt`: close/disconnect와 concurrent request 회귀를 유지한다.
|
|
|
|
테스트 작성: regression test 권장. 많은 client를 만들지 않더라도 read timeout 후 close가 지연 없이 완료되고 concurrent request가 유지되는지 확인한다.
|
|
|
|
중간 검증:
|
|
|
|
```bash
|
|
cd kotlin && ./gradlew --offline test
|
|
```
|
|
|
|
예상 결과: exit 0, TCP 관련 테스트 PASS.
|
|
|
|
### [PERF-2] required skip 제거와 full stress 측정
|
|
|
|
문제: `kotlin/crosstest/stress.kt:198-208`의 `parallelDeadlockBottleneck`이 TCP clients>=128을 required SKIP으로 내보낸다. 이 skip이 남아 있으면 stability가 0이어도 same-language baseline은 INCOMPLETE다.
|
|
|
|
해결 방법:
|
|
|
|
```kotlin
|
|
// before: kotlin/crosstest/stress.kt:198
|
|
private fun parallelDeadlockBottleneck(transport: String, clientCount: Int): String? {
|
|
if (transport == "tcp" && clientCount >= 128) return "deferred: ..."
|
|
return null
|
|
}
|
|
```
|
|
|
|
```kotlin
|
|
// after: shape
|
|
private fun parallelDeadlockBottleneck(transport: String, clientCount: Int): String? = null
|
|
```
|
|
|
|
- skip 제거는 runtime fix 후에만 수행한다.
|
|
- `kotlin/crosstest/stress.kt:549-598`의 full clientCounts `[16,128,512,1024]`는 유지한다.
|
|
- full stress에서 clients=128/512/1024 row가 모두 출력되어야 한다.
|
|
|
|
수정 파일 및 체크리스트:
|
|
|
|
- [ ] `kotlin/crosstest/stress.kt`: TCP parallel required skip 제거.
|
|
- [ ] `kotlin/crosstest/stress.kt`: 필요 시 progress log만 추가하고 matrix는 유지한다.
|
|
|
|
테스트 작성: full stress가 통합 회귀다. unit test는 PERF-1에서 작성한다.
|
|
|
|
중간 검증:
|
|
|
|
```bash
|
|
bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_stress.sh --full --lang kotlin --transport tcp --profile parallel
|
|
```
|
|
|
|
예상 결과: exit 0, Kotlin TCP clients=128/512/1024 row가 SKIP 없이 PASS, required skip 0.
|
|
|
|
## 수정 파일 요약
|
|
|
|
| 파일 | 항목 |
|
|
|---|---|
|
|
| `kotlin/src/main/kotlin/com/tokilabs/proto_socket/TcpClient.kt` | PERF-1 |
|
|
| `kotlin/src/main/kotlin/com/tokilabs/proto_socket/BaseClient.kt` | PERF-1 |
|
|
| `kotlin/src/test/kotlin/com/tokilabs/proto_socket/TcpTest.kt` | PERF-1 |
|
|
| `kotlin/crosstest/stress.kt` | PERF-2 |
|
|
|
|
## 최종 검증
|
|
|
|
```bash
|
|
cd kotlin && ./gradlew --offline test
|
|
bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_stress.sh --full --lang kotlin --transport tcp --profile parallel
|
|
```
|
|
|
|
예상 결과: 모든 명령 exit 0. full stress 결과에서 Kotlin TCP parallel clients=128/512/1024가 required SKIP 없이 측정되고 timeout/nonce/type/FIFO/pending leak이 모두 0이다.
|
|
|
|
모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.
|