--- 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]]