Conversation
WalkthroughDebezium 설정 바인딩 모델, 클라이언트/타임아웃 속성, 전용 RestTemplate, Debezium 커넥터 관리 서비스·초기화 컴포넌트, 관련 예외·에러코드, 비동기/재시도 설정 및 Apache HTTP Client 의존성이 추가되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant App as Application
participant Init as DebeziumConnectorInitializer
participant Service as DebeziumConnectorService
participant Props as DebeziumProperties
participant RT as Debezium RestTemplate
participant Connect as Debezium Connect (HTTP)
App->>Init: ApplicationReadyEvent (비동기)
Init->>Service: registerConnector()
Service->>Props: toConnectorRequest() / toConnectorConfigMap()
Service->>RT: GET /connectors/{name}
alt exists (200)
RT-->>Service: 200 OK
Service->>RT: PUT /connectors/{name}/config
RT-->>Service: 2xx
else not found (404)
RT-->>Service: 404
Service->>RT: POST /connectors
RT-->>Service: 2xx
end
loop poll until RUNNING/FAILED/timeout
Service->>RT: GET /connectors/{name}/status
RT-->>Service: status payload
end
Service-->>Init: 완료 / 상태 로그
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorService.kt (2)
17-21: Gson 기본값으로 인해 Spring Bean 주입이 무시될 수 있습니다.생성자 파라미터에 기본값
Gson()이 있으면 Spring이 Gson Bean을 주입하지 않고 기본값을 사용합니다. 프로젝트에 커스텀 Gson 설정이 있다면 적용되지 않을 수 있습니다.@Service class DebeziumConnectorService( private val debeziumProperties: DebeziumProperties, - private val restTemplate: RestTemplate, - private val gson: Gson = Gson() + private val restTemplate: RestTemplate ) { + private val gson = Gson() private val log = LoggerFactory.getLogger(this::class.java)또는 프로젝트에 Gson Bean이 정의되어 있다면 기본값을 제거하세요:
- private val gson: Gson = Gson() + private val gson: Gson
66-72:RestTemplate은 4xx/5xx 응답 시 예외를 던지므로 else 분기에 도달하지 않습니다.
RestTemplate은 기본적으로 4xx/5xx HTTP 상태 코드에 대해HttpStatusCodeException을 던집니다. 따라서response.statusCode.is2xxSuccessful이 false인 경우 else 분기에 도달하기 전에 예외가 발생합니다.else 분기를 제거하거나, 커스텀
ResponseErrorHandler를 설정하여 예외 없이 응답을 처리하도록 변경할 수 있습니다:if (response.statusCode.is2xxSuccessful) { log.info("Debezium 커넥터가 성공적으로 생성됨: {}", debeziumProperties.connector.name) log.debug("응답: {}", response.body) - } else { - log.error("커넥터 생성 실패. 상태: {}, 응답: {}", response.statusCode, response.body) - throw DebeziumConnectorException }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
📒 Files selected for processing (5)
src/main/kotlin/dsm/pick2024/global/config/debezium/DebeziumProperties.kt(1 hunks)src/main/kotlin/dsm/pick2024/global/error/exception/ErrorCode.kt(1 hunks)src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorInitializer.kt(1 hunks)src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorService.kt(1 hunks)src/main/kotlin/dsm/pick2024/infrastructure/debezium/exception/DebeziumConnectorException.kt(1 hunks)
🔇 Additional comments (5)
src/main/kotlin/dsm/pick2024/global/error/exception/ErrorCode.kt (1)
59-60: LGTM!Debezium 커넥터 오류를 위한 새로운 에러 코드가 적절하게 추가되었습니다. HTTP 500 상태 코드와 한국어 메시지가 기존 에러 코드들과 일관성을 유지합니다.
src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorInitializer.kt (1)
9-38: LGTM!초기화 로직이 잘 구성되어 있습니다:
@ConditionalOnProperty를 통한 조건부 활성화ApplicationReadyEvent를 사용한 적절한 초기화 시점- 외부 서비스 의존성에 대한 적절한 예외 처리 (애플리케이션 시작 차단 방지)
주석으로 설계 의도가 잘 문서화되어 있습니다.
src/main/kotlin/dsm/pick2024/global/config/debezium/DebeziumProperties.kt (2)
50-89: LGTM!Debezium MySQL 커넥터 설정 맵이 올바르게 구성되어 있습니다. Outbox Event Router 변환 설정도 적절히 포함되어 있습니다.
4-7:@ConstructorBindingis required for Spring Boot 2.7.16.This project uses Spring Boot 2.7.16, where
@ConstructorBindingis still necessary and not deprecated. (Note:@ConstructorBindingdeprecation only applies to Spring Boot 3.x where constructor binding is automatic for single-constructor classes.)The
@ConfigurationPropertiesclass is already properly activated via@ConfigurationPropertiesScaninPick2024ServerApplication.kt, so no additional configuration is needed.src/main/kotlin/dsm/pick2024/infrastructure/debezium/exception/DebeziumConnectorException.kt (1)
6-8: No changes needed. The singleton exception pattern used inDebeziumConnectorExceptionis consistent with the entire codebase—all 48 custom exceptions in the project follow this sameobjectpattern extendingPickException. This is the established convention.Likely an incorrect or invalid review comment.
src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorService.kt
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorInitializer.kt (1)
33-37: 외부 서비스 의존성에 대한 장애 격리 전략이 적절합니다.Debezium이 외부 서비스이므로 초기화 실패 시에도 애플리케이션을 시작하도록 구성한 설계가 합리적입니다. 주석에서 대안적인 동작(서비스 중단)을 구현하는 방법도 명확히 설명하고 있습니다.
다만, 커넥터 초기화 실패 시 모니터링 알림을 설정하여 운영팀이 문제를 인지할 수 있도록 하는 것을 권장합니다.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
📒 Files selected for processing (1)
src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorInitializer.kt(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Check Code Quality
🔇 Additional comments (2)
src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorInitializer.kt (2)
9-15: 조건부 빈 등록 설정이 올바릅니다.
@ConditionalOnProperty를 사용하여debezium.enabled=true일 때만 활성화되도록 구성한 것이 적절합니다.matchIfMissing=false설정으로 명시적 opt-in을 요구하는 것도 좋은 설계입니다.
16-18: 생성자 주입 방식이 적절합니다.의존성을 생성자를 통해 주입받고
private val로 불변성을 보장하는 것은 Spring과 Kotlin의 모범 사례입니다.
src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorInitializer.kt
Show resolved
Hide resolved
|
코드래빗 코멘트 해결해주세요 |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/main/kotlin/dsm/pick2024/global/config/restemplate/RestTemplateConfig.kt (1)
13-20: RestTemplate 타임아웃 설정은 적절하지만, RestTemplateBuilder를 사용하면 Boot 친화적으로 정리할 수 있습니다.현재 구현(명시적인 connect/read timeout +
HttpComponentsClientHttpRequestFactory)은 기능적으로 문제 없어 보입니다. 다만 Spring Boot 환경이라면RestTemplateBuilder와Duration을 활용하면 설정이 더 명확해지고, 전역적으로 커스터마이징된 빌더 설정(인터셉터, 메시지 컨버터 등)을 그대로 재사용할 수 있습니다.아래와 같이 리팩터링을 고려해 볼 수 있습니다 (선택 사항):
- @Bean - fun restTemplate(): RestTemplate { - val factory = HttpComponentsClientHttpRequestFactory().apply { - setConnectTimeout(5000) - setReadTimeout(10000) - } - - return RestTemplate(factory) - } + @Bean + fun restTemplate(builder: RestTemplateBuilder): RestTemplate = + builder + .setConnectTimeout(Duration.ofSeconds(5)) + .setReadTimeout(Duration.ofSeconds(10)) + .build()이 방식이 프로젝트의 Spring Boot 버전 및 기존 RestTemplate 사용 방식과 잘 맞는지는 한 번만 확인해 주시면 좋겠습니다.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
📒 Files selected for processing (1)
src/main/kotlin/dsm/pick2024/global/config/restemplate/RestTemplateConfig.kt(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Check Code Quality
🔇 Additional comments (1)
src/main/kotlin/dsm/pick2024/global/config/restemplate/RestTemplateConfig.kt (1)
3-8: Debezium HTTP 호출을 위한 RestTemplate 관련 import 추가는 현재 구현과 잘 맞습니다.새로 도입된 RestTemplate 설정(시간 제한 및 HttpComponents 사용)을 고려했을 때, 필요한 import 구성이 자연스럽고 일관성 있어 보입니다.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
📒 Files selected for processing (1)
src/main/kotlin/dsm/pick2024/global/config/restemplate/RestTemplateConfig.kt(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Check Code Quality
src/main/kotlin/dsm/pick2024/global/config/restemplate/RestTemplateConfig.kt
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/main/kotlin/dsm/pick2024/global/config/restemplate/RestTemplateProperties.kt (1)
1-11: RestTemplateProperties 구성 클래스 정의는 적절하며, 필요 시 Duration 타입으로의 확장 여지가 있습니다
rest-template프리픽스로 타임아웃 설정을 한 곳에 모아두어 설정 가독성과 관리성이 좋아졌고, 기본값도 기존 하드코딩 값(5000/10000ms)과 동일해 동작이 유지됩니다.- 향후
application.yml에서5s,10s같은 표현으로 타임아웃을 더 유연하게 지정하고 싶다면,Int대신Duration타입으로 선언한 뒤RestTemplateConfig에서toMillis().toInt()로 변환하는 패턴도 고려해 볼 수 있습니다. 지금 구조도 충분히 실용적이니 꼭 바꿀 필요는 없고, 설정 유연성이 필요해질 때 선택지로 생각해 두시면 될 것 같습니다.buildSrc/src/main/kotlin/Dependencies.kt (1)
52-54: Dependencies.APACHE_HTTP_CLIENT 상수 추가로 빌드 스크립트 일관성이 좋아졌습니다
APACHE_HTTP_CLIENT를 별도 상수로 정의하고DependencyVersions.APACHE_HTTP_CLIENT와 연동해,build.gradle.kts쪽에서 중복 문자열 없이 의존성을 선언할 수 있게 된 점이 좋습니다.
추가로, 프로젝트 내에서 HTTP 호출이 RestTemplate+Apache HttpClient 조합 외에 다른 스택(WebClient, Reactor Netty 등)과 혼재되어 있다면, 어느 경로가 어떤 용도로 쓰이는지(예: Debezium용 전용 RestTemplate vs 일반 외부 API용) 간략히 정리해 두시면 장애 분석이나 성능 튜닝 시에 도움이 될 것 같습니다.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
📒 Files selected for processing (5)
build.gradle.kts(1 hunks)buildSrc/src/main/kotlin/Dependencies.kt(1 hunks)buildSrc/src/main/kotlin/DependencyVersions.kt(1 hunks)src/main/kotlin/dsm/pick2024/global/config/restemplate/RestTemplateConfig.kt(1 hunks)src/main/kotlin/dsm/pick2024/global/config/restemplate/RestTemplateProperties.kt(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Check Code Quality
🔇 Additional comments (3)
build.gradle.kts (1)
83-85: Apache HTTP Client 의존성 추가로 RestTemplateConfig 런타임 이슈가 해소되었습니다
HttpComponentsClientHttpRequestFactory를 사용하는RestTemplateConfig와 맞게Dependencies.APACHE_HTTP_CLIENT를 별도 의존성으로 선언해서, 런타임ClassNotFoundException리스크를 잘 제거하셨습니다. 빌드 스크립트 구조(DependencyVersions/Dependencies 경유)와도 일관성이 있습니다.
다만4.5.14버전이 현재 인프라의 보안·호환성 기준(예: 사용 중인 Spring Boot/Spring Framework 버전, 사내 CVE 정책 등)에 부합하는지는 한 번 더 점검해 주세요.buildSrc/src/main/kotlin/DependencyVersions.kt (1)
17-17: APACHE_HTTP_CLIENT 버전 상수 정의가 의존성 관리 흐름과 잘 맞습니다
Dependencies.APACHE_HTTP_CLIENT와 연결되는APACHE_HTTP_CLIENT = "4.5.14"상수를 별도로 둬서 버전 관리가 중앙집중화된 점이 좋습니다. 다른 라이브러리 버전 상수들과도 포맷이 일관적입니다.
운영 환경 보안 정책(CVE 대응, 장기 지원 여부 등)에 맞는 버전인지, 그리고 프로젝트에서 사용하는 Spring 생태계 버전과의 호환성은 주기적으로 한 번씩 점검해 두시면 좋겠습니다.src/main/kotlin/dsm/pick2024/global/config/restemplate/RestTemplateConfig.kt (1)
5-20: RestTemplate 타임아웃 외부화와 HttpComponents 팩토리 적용이 깔끔하게 정리되었습니다
RestTemplateConfig가RestTemplateProperties를 생성자 주입받고,HttpComponentsClientHttpRequestFactory에connectTimeoutMs/readTimeoutMs를 적용하는 구조라서 환경별 타임아웃 조정이 용이해졌습니다.- 기존과 동일한 시그니처의
@Bean fun restTemplate(): RestTemplate를 유지하고 있어, Debezium 연동을 포함한 기존 RestTemplate 주입 코드와도 호환성이 좋아 보입니다.- 다만
RestTemplateProperties가 실제로 바인딩되려면 어딘가에서@ConfigurationPropertiesScan또는@EnableConfigurationProperties(RestTemplateProperties::class)가 선언되어 있어야 합니다. 이미 글로벌 설정에 포함되어 있다면 그대로 두셔도 되고, 아니라면 해당 애너테이션 추가를 한 번 검토해 주세요.이 변경으로 이전 코드래빗 코멘트에서 지적되었던 httpclient 의존성 누락 및 타임아웃 하드코딩 이슈는 모두 해결된 것으로 보입니다.
handling - Add retry logic with exponential backoff (max 5 attempts) - Implement async initialization to prevent app startup blocking - Add dedicated RestTemplate with extended timeout (60s) - Separate retryable and non-retryable exceptions - Improve status check with polling mechanism (30s max) - Enable @EnableRetry and @EnableAsync configurations
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (2)
src/main/kotlin/dsm/pick2024/infrastructure/debezium/exception/DebeziumConfigurationException.kt (1)
6-8: 동일한 ErrorCode 사용 (중복 지적)이 파일도
DebeziumRetryableException과 동일한ErrorCode.DEBEZIUM_CONNECTOR_ERROR를 사용합니다. 앞서 지적한 것과 동일한 이슈입니다.src/main/kotlin/dsm/pick2024/global/config/debezium/DebeziumClientProperties.kt (1)
6-11: @ConstructorBinding 사용 확인 필요 (중복 지적)
DebeziumRetryProperties와 동일하게@ConstructorBinding어노테이션 사용에 대한 Spring Boot 3.x 호환성 확인이 필요합니다.
🧹 Nitpick comments (2)
src/main/kotlin/dsm/pick2024/infrastructure/debezium/exception/DebeziumRetryableException.kt (1)
6-8: DebeziumConfigurationException과 동일한 ErrorCode 사용
DebeziumRetryableException과DebeziumConfigurationException모두ErrorCode.DEBEZIUM_CONNECTOR_ERROR를 사용하고 있습니다. 재시도 가능한 오류와 설정 오류를 구분하기 위해 별도의 ErrorCode를 사용하는 것이 디버깅과 에러 추적에 더 유용합니다.예:
DEBEZIUM_CONNECTOR_RETRYABLE_ERROR,DEBEZIUM_CONNECTOR_CONFIGURATION_ERRORsrc/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorService.kt (1)
141-165: JSON 파싱 개선 권장 및 블로킹 동작 확인현재 구현에서 두 가지 개선 사항을 고려할 수 있습니다:
문자열 기반 JSON 파싱: 149, 152번 라인에서
status.contains("\"state\":\"RUNNING\"")와 같은 문자열 검색을 사용하고 있습니다. 이미Gson인스턴스가 있으므로, 응답을 적절한 데이터 클래스로 역직렬화하여 타입 안전하게 처리하는 것이 더 견고합니다.Thread.sleep 사용: 159번 라인의
Thread.sleep()은 현재 스레드를 블로킹합니다. 애플리케이션 시작 시에만 호출된다면 문제없지만, 요청 처리 스레드에서 호출될 경우 성능 문제가 발생할 수 있습니다.개선 예시 (JSON 파싱):
data class ConnectorStatus( val name: String, val connector: ConnectorState, val tasks: List<TaskState> ) data class ConnectorState(val state: String) data class TaskState(val state: String) // 사용: val statusObj = gson.fromJson(status, ConnectorStatus::class.java) if (statusObj.connector.state == "RUNNING") { // ... }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
📒 Files selected for processing (8)
src/main/kotlin/dsm/pick2024/global/config/async/AsyncConfig.kt(1 hunks)src/main/kotlin/dsm/pick2024/global/config/debezium/DebeziumClientProperties.kt(1 hunks)src/main/kotlin/dsm/pick2024/global/config/debezium/DebeziumRestTemplateConfig.kt(1 hunks)src/main/kotlin/dsm/pick2024/global/config/debezium/DebeziumRetryProperties.kt(1 hunks)src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorInitializer.kt(1 hunks)src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorService.kt(1 hunks)src/main/kotlin/dsm/pick2024/infrastructure/debezium/exception/DebeziumConfigurationException.kt(1 hunks)src/main/kotlin/dsm/pick2024/infrastructure/debezium/exception/DebeziumRetryableException.kt(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorInitializer.kt
🔇 Additional comments (5)
src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorService.kt (3)
33-41: 재시도 설정 구성 확인
@Retryable어노테이션이 올바르게 구성되어 있습니다. SpEL 표현식을 사용하여DebeziumRetryProperties빈의 속성을 참조하는 방식은 적절합니다.
68-80: 커넥터 존재 여부 확인 로직 양호404 상태 코드를 통해 커넥터 존재 여부를 판단하는 로직이 올바르게 구현되어 있습니다. 다른 클라이언트 에러는 상위로 전파되어 적절히 처리됩니다.
167-176: Fix the exception throw syntax on line 174
DebeziumConnectorExceptionis being thrown without instantiation. In Kotlin, exceptions must be instantiated with parentheses. Changethrow DebeziumConnectorExceptiontothrow DebeziumConnectorException()(or pass a message if the constructor accepts one).src/main/kotlin/dsm/pick2024/global/config/debezium/DebeziumRetryProperties.kt (1)
6-13: > Likely an incorrect or invalid review comment.src/main/kotlin/dsm/pick2024/global/config/debezium/DebeziumRestTemplateConfig.kt (1)
21-24: No changes needed. The project uses Spring Boot 2.7.16 (Spring Framework 5.3.x), wheresetConnectTimeoutandsetReadTimeoutare not deprecated. These methods only become deprecated in Spring Framework 6.0+. The current implementation is appropriate for the Spring version in use.Likely an incorrect or invalid review comment.
src/main/kotlin/dsm/pick2024/global/config/async/AsyncConfig.kt
Outdated
Show resolved
Hide resolved
src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorService.kt
Show resolved
Hide resolved
src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorService.kt
Show resolved
Hide resolved
|
이런; 코드래빗 코멘트 reslove 해주세요 |
…zation - Retry with exponential backoff (5 attempts, 2s-30s) - Async init with bounded ThreadPoolTaskExecutor (core=2, max=5) - Dedicated 60s timeout for connector operations - Exception handling: 4xx (no retry) vs 5xx (retry) - Status polling to wait for RUNNING state
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorService.kt (1)
131-139: 문자열 기반 JSON 상태 파싱은 취약합니다.
status.contains("\"state\":\"RUNNING\"")는 JSON 형식이 변경되거나 공백이 추가되면 실패할 수 있습니다. 이미 주입된Gson을 사용하여 JSON을 파싱하는 것이 안전합니다.+ private data class ConnectorStatus( + val connector: ConnectorState? = null + ) + private data class ConnectorState( + val state: String? = null + ) + fun waitForConnectorReady(maxWaitMs: Long = 30000, pollIntervalMs: Long = 2000): Boolean { val startTime = System.currentTimeMillis() var attempt = 1 while (System.currentTimeMillis() - startTime < maxWaitMs) { val status = getConnectorStatus() if (status != null) { - if (status.contains("\"state\":\"RUNNING\"")) { + val parsed = runCatching { gson.fromJson(status, ConnectorStatus::class.java) }.getOrNull() + val state = parsed?.connector?.state + if (state == "RUNNING") { log.info("Debezium 커넥터가 RUNNING 상태로 전환됨 (시도 횟수: {})", attempt) return true - } else if (status.contains("\"state\":\"FAILED\"")) { + } else if (state == "FAILED") { log.error("Debezium 커넥터가 FAILED 상태로 전환됨: {}", status) return false }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
📒 Files selected for processing (2)
src/main/kotlin/dsm/pick2024/global/config/async/AsyncConfig.kt(1 hunks)src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorService.kt(1 hunks)
🔇 Additional comments (5)
src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorService.kt (3)
24-31: 클래스 구조가 적절합니다.
@Qualifier를 사용하여 전용debeziumRestTemplate을 주입받고, 필요한 의존성들을 잘 구성했습니다. 이전 리뷰에서 지적된 타임아웃 설정도 적용된 것으로 확인됩니다.
69-111: 이전 리뷰 피드백이 잘 반영되었습니다.
createConnector()와updateConnector()메서드에서 도달 불가능한 else 블록이 제거되었고, 예외 처리는 상위registerConnector()메서드에서 일관되게 처리됩니다.
150-159: LGTM!삭제 로직이 간결하고 예외 처리가 적절합니다.
src/main/kotlin/dsm/pick2024/global/config/async/AsyncConfig.kt (2)
26-46: 이전 리뷰 피드백이 잘 반영되었습니다.
AsyncConfigurer를 구현하고ThreadPoolTaskExecutor를 사용하여 스레드 풀을 적절히 구성했습니다. 거부된 작업에 대한 핸들러와 graceful shutdown 설정도 포함되어 있습니다.
48-58: LGTM!비동기 작업에서 발생하는 처리되지 않은 예외를 적절히 로깅하고 있습니다.
src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorService.kt
Outdated
Show resolved
Hide resolved
…zation - Retry with exponential backoff (5 attempts, 2s-30s) - Async init with bounded ThreadPoolTaskExecutor (core=2, max=5) - Dedicated 60s timeout for connector operations - Exception handling: 4xx (no retry) vs 5xx (retry) - Status polling to wait for RUNNING state
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorService.kt (3)
63-75:ResourceAccessException와 소켓 관련 예외 캐치가 중복될 가능성이 큽니다.Spring
RestTemplate는 보통ConnectException,SocketTimeoutException,UnknownHostException같은 I/O 예외를ResourceAccessException으로 래핑해서 던지기 때문에, 현재 구조에서는 뒤쪽의 개별catch (SocketTimeoutException / ConnectException / UnknownHostException)블록이 실제로는 거의 실행되지 않을 수 있습니다.
ResourceAccessException한 곳에서e.cause타입을 검사해 세분화해서 로그를 찍거나, 필요 없다면 개별 캐치 블록을 정리해 예외 처리를 단순화하는 쪽을 고려해 보셔도 좋겠습니다.
125-133: 상태 조회 실패 로그에 스택트레이스를 함께 남기는 것이 좋습니다.현재는
e.message만 로깅하고 있어서, 장애 시 원인 추적이 어려울 수 있습니다. 아래처럼 exception 객체도 같이 넘기는 편이 디버깅에 유리합니다.- } catch (e: Exception) { - log.error("커넥터 상태 조회 실패: {}", e.message) - null - } + } catch (e: Exception) { + log.error("커넥터 상태 조회 실패: {}", e.message, e) + null + }
136-160:waitForConnectorReady가 호출 스레드를 블로킹하며, 상태 파싱이 문자열 의존적입니다.초기화 단계에서만 쓰인다면 괜찮을 수 있지만, 다른 곳에서 재사용될 여지가 있다면
Thread.sleep기반 루프는 최대 30초 동안 스레드를 점유하므로 주의가 필요합니다. 호출 측에서 이 메서드가 블로킹이라는 점을 명확히 인지하고 사용하는지 한 번 더 점검해 보시는 것을 권장합니다.또한 상태 응답을
status.contains("\"state\":\"RUNNING\"")식으로 문자열 검색하는 대신, Gson 등으로 JSON 을 파싱해서state필드만 비교하면 향후 응답 포맷 변경에 덜 민감한 구현이 될 것입니다.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
📒 Files selected for processing (1)
src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorService.kt(1 hunks)
🔇 Additional comments (1)
src/main/kotlin/dsm/pick2024/infrastructure/debezium/DebeziumConnectorService.kt (1)
37-79: 등록 플로우와 재시도 설정 구조는 전반적으로 잘 잡혀 있습니다.예외 유형별로 재시도 가능/불가능을 명확히 나누고,
@Retryable로 재시도 정책을 외부 설정(DebeziumRetryProperties)에 위임한 부분은 운영/튜닝 관점에서 이해하기 좋은 구성입니다.
|
@ByunDohwi 수정 다했으니까 코드 한번보고 머지해주세요. |
Debezium MySQL Connetcor를 자동으로 등록하도록 구현했습니다.
Summary by CodeRabbit
신규 기능
개선 사항
잡무
✏️ Tip: You can customize this high-level summary in your review settings.