서버 간 통신 중, 간헐적으로 다음과 같은 에러들이 발생
recvAddress(..) failed: Connection reset by peer
handshake timed out after 10000ms
을 동반Connection prematurely closed BEFORE response
@Bean(WebClientName.API_WEB_CLIENT)
fun getClient(): WebClient {
val httpClient: HttpClient = HttpClient
.create(
ConnectionProvider.builder("ApiConnections")
.maxConnections(maxConnections) // maxConnections는 프로퍼티로 관리
.maxIdleTime(Duration.ofSeconds(30))
.pendingAcquireTimeout(Duration.ofSeconds(45))
.evictInBackground(Duration.ofSeconds(30))
.lifo()
.metrics(true)
.build()
)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000 * 30)
.doOnConnected {
it
.addHandlerLast(ReadTimeoutHandler(45, TimeUnit.SECONDS))
.addHandlerLast(WriteTimeoutHandler(10, TimeUnit.SECONDS))
}
.responseTimeout(Duration.ofSeconds(60))
.secure {
it
.sslContext(DefaultSslContextSpec.forClient())
.handshakeTimeout(Duration.ofSeconds(20))
}
.headers{
it.add(HttpHeaders.ACCEPT_LANGUAGE, "ko")
}
return WebClient.builder()
.baseUrl(url)
.clientConnector(ReactorClientHttpConnector(httpClient))
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build()
}
ConnectionProvider
maxConnections
: 커넥션 풀 별 최대 커넥션 개수를 설정한다. 기본값은 (사용가능한 프로세서 수 * 2)와 16 중 큰 값.maxIdleTime
: 커넥션이 유휴 상태일 때, 얼마나 유지할지를 정한다. 기본값은 없음. (not specified.)evictInBackground
: 설정한 시간마다 maxIdleTime
기준으로 정리할 유휴 커넥션들을 체크하고 커넥션을 제거한다. 기본값은 비활성.metrics
: actuator metric에 노출한다.apiWebClient.post()
.uri(API_URL)
.bodyValue(requestDto)
.retrieve()
.bodyToMono(ApiResponseDto::class.java)
.retry(2)
.onErrorMap { throw ApiException(it.message ?: "Unexpected Exception Occurred.") }
.block()!!
retry
: 요청이 실패할 경우 자동으로 재시도한다.