Files
llm-wiki/raw/errors/sample-portfolio-tomcat-port-in-use-check-2026-07-03.md
T

79 lines
4.8 KiB
Markdown

---
title: error / sample portfolio Tomcat port in use during check (2026-07-03)
source_type: error-note
status: raw
related_branches: [feature-startup-failure-log-suppression, feature-sample-portfolio-public-access]
related_projects: [ca-tmpl]
tags: [error, ca-tmpl, testing, spring-boot, networking]
created: 2026-07-03
status_label: resolved
---
# error: sample-portfolio-tomcat-port-in-use-check
## Parent / 부모
- [[raw/branch-notes/feature-startup-failure-log-suppression]]
- [[raw/branch-notes/feature-sample-portfolio-public-access]]
## 증상 / Symptom
- 에러 메시지 (원문 그대로):
```text
OpenApiDriftContractTest > runtimeOpenapiDocMatchesCommittedSnapshot() FAILED
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:195
Caused by: org.springframework.context.ApplicationContextException at DefaultLifecycleProcessor.java:423
Caused by: org.springframework.context.ApplicationContextException at DefaultLifecycleProcessor.java:423
Caused by: org.springframework.boot.web.server.PortInUseException at PortInUseException.java:73
Caused by: java.lang.IllegalArgumentException at StandardService.java:220
Caused by: org.apache.catalina.LifecycleException at Connector.java:1107
Caused by: java.net.BindException at Net.java:-2
```
- 발생 컨텍스트: `cd src && ./gradlew check`.
- 발생 시점: 2026-07-03 10:47 KST.
- 발생 환경: local ca-tmpl workspace.
- 재현 가능 여부: `once` — 전체 check 재실행 중 sample-portfolio SpringBootTest들이 Tomcat port binding에 실패.
## 재현 절차 / Reproduction
1. ca-tmpl `src/`에서 `./gradlew check`를 실행한다.
2. `:sample-portfolio:test`가 실행된다.
3. 기대 결과는 전체 check green이지만 실제 결과는 6개 sample-portfolio tests가 `PortInUseException`/`BindException`으로 실패한다.
## 조사 단계 / Investigation log
- 2026-07-03 10:45 — startup failure hardening 후 `./gradlew check` 첫 실행 → Spotless import order 실패.
- 2026-07-03 10:46 — import order 수정 후 `./gradlew check` 재실행 → `:sample-portfolio:test`에서 6개 test 실패.
- 2026-07-03 10:47 — 실패 test 목록 확인 → `OpenApiDriftContractTest`, `DateHeaderContractTest`, `VirtualThreadMdcE2ETest`, `OpenApiSnapshotTest` 모두 Spring context load 중 Tomcat `PortInUseException`.
- 2026-07-03 10:47 — 같은 변경 범위의 focused suite, `:app-bootstrap:test`, `verifyCleanArchitectureDependencies`, DB-down bootRun, invalid-tracing bootRun은 이미 green/expected failure로 검증됨.
- 2026-07-03 11:14 — sample public access 작업 중 failing tests에 `management.server.port=0`을 명시하고 `:sample-portfolio:test`를 재실행 → 142 tests green.
- 2026-07-03 11:15 — `./gradlew check` 재실행 → 전체 check green.
## 근본 원인 / Root cause
- 직접 원인: sample-portfolio test context가 필요한 Tomcat port를 bind하지 못했다.
- 근본 원인: sample-portfolio web integration tests가 `application.yml`의 `management.server.port=${MANAGEMENT_SERVER_PORT:9001}` 기본값을 상속했고, 로컬에서 9001을 이미 사용 중인 Java process가 있어 management Tomcat bind가 실패했다.
- 트리거 조건: 전체 `./gradlew check`가 sample-portfolio web integration tests를 실행하는 동안 port collision이 발생.
## Sources / 근거
- [[raw/branch-notes/feature-startup-failure-log-suppression]] — 이번 check 실패가 발생한 작업 branch.
- local command evidence — `./gradlew check` output의 `PortInUseException`/`BindException` stack summary.
## 해결 / Resolution
- 적용한 조치: `OpenApiSnapshotTest`, `OpenApiDriftContractTest`, `DateHeaderContractTest`, `VirtualThreadMdcE2ETest`에 `management.server.port=0`을 명시해 test-only management server port를 랜덤화했다.
- 검증 방법: `./gradlew :sample-portfolio:test` 통과, `./gradlew check` 통과.
- 잔여 위험 / 후속 작업: runtime 기본 `9001`은 유지되므로 실제 sample app 실행 시 동일 포트가 이미 사용 중이면 여전히 충돌할 수 있다. 테스트 격리 문제는 해소됨.
## 회고 / Lessons
- 빨리 감지하는 신호: 전체 `check`에서 여러 SpringBootTest가 동시에 `PortInUseException`이면 기능 회귀보다 test/runtime port collision을 먼저 의심한다.
- 예방 체크리스트 항목 후보: web integration tests는 random port 또는 deterministic isolated port strategy를 강제한다.
- wiki로 끌어올릴 가치가 있는 일반화된 교훈: local full-check 실패는 변경 범위 focused verification과 실패 모듈의 root cause를 분리해 보고해야 한다.
## Related / 관련
- [[raw/errors/bootstrap-postgres-port-collision-2026-06-24]]
- [[raw/branch-notes/feature-sample-portfolio-public-access]]