티스토리 뷰
기능을 구현하려는데 라이브러리를 사용하려는 뭔가 복잡하고, 이해하기 힘든다는 생각이 들면, 그 라이브러리 탓이지 사용하는 개발자 문제가 아니다. 기본적으로 프로그램은 은닉성이 중요한데, 내부 동작을 알고 작업해야 한다는 것은 그 프로그램의 심각한 결함이 있다는 말이다. circuit breaker는 그냥 호출하는 서비스가 죽었을 때 대처하는 방법을 우아하게 한 것 뿐이다. 예전에 try catch 에서 다 하던 거라 별 것 없다.
1. io.github.resilience4j:resilience4j-spring-boot3 의존성 사용하여 구현한다면 웬만하면 이 설정 부분 만큼은 자바 쓰는 게 낫다. 설정 많이 추가해서 코클린 컴파일 하는 것 보다 default interface를 자바로 구현하는 것이 안전하다.
2. 이런 cloud api 들은 설정 문제인지 코드 문제인지 혼동되는 경우가 많다. resilience4j 같은 범용 코드는 kotlin을 공식지원하는 spring 프레임워크와 다른 정책을 가지고 있다.
// 동작하지 않는 코드
package net.philipheur.hshop.catalogservice.exchange
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker
import net.philipheur.hshop.catalogservice.domain.service.dto.SearchResponse
import net.philipheur.hshop.common.domain.dtos.settings.SettingDto
import org.springframework.cloud.openfeign.FeignClient
import org.springframework.web.bind.annotation.GetMapping
import java.util.Locale
import java.util.UUID
@FeignClient(name = "settings-service")
interface SettingsServiceClient {
@GetMapping(value = ["/api/settings"])
@CircuitBreaker(name = "settings-service", fallbackMethod = "findAllSettingFallBack")
fun findAllSettings(): SearchResponse<SettingDto>
private fun findAllSettingFallBack(exception: Throwable): SearchResponse<SettingDto> {
print("circuit break default function executed")
val locale = Locale.getDefault()
locale.displayCountry
locale.language
println("${locale.displayCountry}, ${locale.language}")
return SearchResponse(
totalElements = 1,
totalPages = 1,
pageNo = 0,
pageSize = 1,
last = true,
content = listOf(SettingDto(
id = UUID.randomUUID().toString(),
key = "CURRENCY",
value = "ko,KR",
category = "GENERAL"
))
)
}
}
// 그냥 자바로 구현하는 게 낫다.
@FeignClient(name = "settings-service")
public interface SettingsServiceClient {
@GetMapping(value = "/api/settings")
@CircuitBreaker(name = "settings-service", fallbackMethod = "findAllSettingFallBack")
SearchResponse<SettingDto> findAllSettings();
default SearchResponse<SettingDto> findAllSettingFallBack(Throwable exception) {
System.out.println("circuit break default function executed");
var locale = Locale.getDefault();
System.out.println(locale.getDisplayCountry() + " " + locale.getLanguage());
return new SearchResponse<>(
1,
1,
0,
1,
true,
List.of(new SettingDto(
UUID.randomUUID().toString(),
"CURRENCY",
"ko,KR",
"GENERAL"
))
);
}
}
3. 위의 방식으로 구현하는 것보다 spring-cloud-starter-circuitbreaker-resilience4j 를 바로 추가해서 fallback 클래스를 구현하는 방법도 있다. 아래 방법이 좀 더 깔끔해 보이고 resilience4j를 바로 import하지 않아도 되기 때문에 다른 기능이 필요없으면 이런 식으로도 가능하다.
3-1 io.github.resilience4j:resilience4j-spring-boot3를 제거하고 spring-cloud-starter-circuitbreaker-resilience4j 를 추가한다.
3-2 아래를 사용하려면 resilience4j 설정 이외에도 아래 설정의 추가가 필요하다. application.yml에 추가 한다.
cloud:
openfeign:
circuitbreaker:
enabled: true
// @Feign Client
package net.philipheur.hshop.catalogservice.exchange;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker
import net.philipheur.hshop.catalogservice.domain.service.dto.SearchResponse
import net.philipheur.hshop.common.domain.dtos.settings.SettingDto
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping
import java.util.*
@FeignClient(name = "settings-service", fallback = SettingServiceClientFallback::class)
interface SettingsServiceClient {
@GetMapping(value = ["/api/settings"])
fun findAllSettings(): SearchResponse<SettingDto>
}
// fallback 클래스
package net.philipheur.hshop.catalogservice.exchange
import net.philipheur.hshop.catalogservice.domain.service.dto.SearchResponse
import net.philipheur.hshop.common.domain.dtos.settings.SettingDto
import org.springframework.stereotype.Component
import java.util.*
@Component
class SettingServiceClientFallback : SettingsServiceClient {
override fun findAllSettings(): SearchResponse<SettingDto> {
println("circuit break default function executed")
val locale = Locale.getDefault();
return SearchResponse(
totalElements = 1,
totalPages = 1,
pageNo = 0,
pageSize = 1,
last = true,
content = listOf(
SettingDto(
id = UUID.randomUUID().toString(),
key = "CURRENCY",
value = "${locale.language},${locale.country}",
category = "GENERAL"
)
)
)
}
}
'기록' 카테고리의 다른 글
nginx : 도커 이미지 기본 forwarding (0) | 2024.04.04 |
---|---|
VS Code React, Next 에서 double quotes 사용하기 (0) | 2024.03.26 |
Android: 사오미 폰 다른 앱 switching 시에 process termination (0) | 2023.06.05 |
[Android] LazyColumn이 아닌 swipeToDismiss로 Carousal 구현 (0) | 2023.05.05 |
코딩 면접에 대해서 (0) | 2023.04.02 |
- Total
- Today
- Yesterday
- 도커 개발환경 참고
- AWS ARN 구조
- Immuability에 관한 설명
- 자바스크립트 멀티 비동기 함수 호출 참고
- WSDL 참고
- SOAP 컨슈머 참고
- MySql dump 사용법
- AWS Lambda with Addon
- NFC 드라이버 linux 설치
- electron IPC
- mifare classic 강의
- go module 관련 상세한 정보
- C 메모리 찍어보기
- C++ Addon 마이그레이션
- JAX WS Header 관련 stackoverflow
- SOAP Custom Header 설정 참고
- SOAP Custom Header
- SOAP BindingProvider
- dispatcher 사용하여 설정
- vagrant kvm으로 사용하기
- git fork, pull request to the …
- vagrant libvirt bridge network
- python, js의 async, await의 차이
- go JSON struct 생성
- Netflix Kinesis 활용 분석
- docker credential problem
- private subnet에서 outbound IP 확…
- 안드로이드 coroutine
- kotlin with, apply, also 등
- 안드로이드 초기로딩이 안되는 경우
- navigation 데이터 보내기
- 레이스 컨디션 navController
- raylib
- one-to-many
- spring boot
- 로그인
- 스프링부트
- Validation
- login
- MYSQL
- Security
- jsp
- XML
- Many-To-Many
- 하이버네이트
- hibernate
- crud
- Spring
- 스프링
- mapping
- 매핑
- 외부파일
- one-to-one
- Angular
- Spring Security
- 설정하기
- RestTemplate
- 설정
- 상속
- Rest
- form
- WebMvc
- 자바