4.9 KiB
title, source_type, status, related_branches, related_projects, tags, created, status_label, target_audience, inspiration_url, archive_url
| title | source_type | status | related_branches | related_projects | tags | created | status_label | target_audience | inspiration_url | archive_url | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| HikariCP knob 간 제약을 Spring Boot 시작 guard 로 강제하는 패턴 | blog-topic | raw |
|
|
|
2026-06-09 | ready-for-canonical | backend-engineer |
HikariCP inter-knob constraints as a Spring Boot startup guard
Parent
트리거 / Trigger
- 트리거 유형:
branch-work - 트리거 날짜: 2026-06-09
- 트리거 연결 노트: raw/branch-notes/feature-database-connection-pool-contract
글감 / Topic seed
- 한 문장 요지: HikariCP knob 간 제약을 runtime 경고에 맡기지 않고 Spring Boot startup guard로 수집해 fail-fast시키는 패턴이다.
- 예상 제목 후보:
- HikariCP 설정 오류를 startup에서 잡기
- Connection pool knob 제약을 Spring Boot guard로 고정하기
핵심 주장 후보 / Claim candidates
- 사실 후보:
validationTimeout < connectionTimeout,keepaliveTime < maxLifetime같은 inter-knob 제약이 있다.SmartInitializingSingleton과ApplicationContextRunner로 startup guard를 검증할 수 있다.
- 의견/해석 후보:
- pool 설정 오류는 traffic을 받기 전 startup phase에서 실패시키는 편이 운영적으로 더 명확하다.
Outline seed
- HikariCP knob 간 제약과 runtime 경고/reset의 한계를 정리한다.
- String 기반 defensive parse로 Duration drift를 안전하게 처리한다.
ApplicationContextRunner로 guard failure를 작은 테스트로 고정한다.
핵심 아이디어
HikariCP 에는 knob 간 순서 제약이 있다:
validationTimeout < connectionTimeoutkeepaliveTime < maxLifetimeconnectionTimeout >= 250 msleakDetectionThreshold >= 2000 ms(0 = disabled 허용)
이 제약들은 HikariCP 내부에서 경고 또는 reset 으로만 처리되고, 설정 오류가 runtime 에서만 드러나는 경우가 많다. SmartInitializingSingleton + Environment.getProperty(key) (String, not typed) 패턴으로 context refresh 완료 직전에 모든 위반을 한꺼번에 수집해 IllegalStateException 으로 boot fail 시키면, 잘못된 pool 설정이 prod 에 배포되는 것을 막을 수 있다.
흥미로운 구현 포인트
Defensive parseMillis (CONNECTION_TIMEOUT_FORMAT_DRIFT)
environment.getProperty("spring.datasource.hikari.connection-timeout", Long.class) 는 env-keys.yaml default 가 "5s" (Duration string) 일 때 ConversionFailedException 을 던진다. 대신 getProperty(key) 로 String 을 받아 Long.parseLong(raw.trim()) + NumberFormatException catch → return null 패턴으로 방어 파싱하면:
- 숫자 ms 값은 정상 검증
- Duration string 은 null (absent 취급) — 크래시 없이 skip
- 명세에서 두 포맷이 공존하는 drift 환경에서 안전
ApplicationContextRunner 기반 단위 테스트
@SpringBootTest 없이 ApplicationContextRunner.withUserConfiguration(ValidatorConfig.class) 만으로 SmartInitializingSingleton 의 afterSingletonsInstantiated() 가 호출된다. context.hasFailed() + context.getStartupFailure().hasStackTraceContaining(...) 으로 각 위반 케이스를 격리 검증.
글감 방향
- Spring Boot startup contract 패턴 시리즈 (
SmartInitializingSingletonvsApplicationListener<ContextRefreshedEvent>vs@PostConstruct) - HikariCP 운영에서 놓치기 쉬운 knob 간 제약 총정리
- "설정 오류를 runtime 이 아닌 startup 에서 잡는다" 원칙의 구현 패턴들
Canonical 전환 후보 / Canonical extraction candidates
wiki/projects/ca-tmpl/data-layer-persistence-cache-outbound.md후보:- HikariCP inter-knob constraint startup guard를 data-layer/pool configuration 글감으로 연결.
- 필요한 추가 검증:
- 실제 validator class,
ApplicationContextRunner테스트, env duration drift 처리 범위.
- 실제 validator class,
Sources / 근거 후보
미해결 / Unknown
- 아직 확인해야 할 사실: 현재 ca-tmpl 코드에 startup guard와 관련 테스트가 존재하는지.
- 과장하면 안 되는 부분: HikariCP 자체가 모든 오류를 방치한다고 쓰지 않고, ca-tmpl에서 선택한 fail-fast 보강으로 제한한다.
Related / 관련
Decision / 처리 결정
- 액션:
promote-to-canonical - 이유:
wiki/projects/ca-tmpl/data-layer-persistence-cache-outbound.md에 HikariCP startup guard 글감으로 반영했다. - 다음 단계: target canonical이 아직
draft이므로blogify전 pool guard 구현·검증 여부를 branch-note/code 기준으로 확인한다.