resilience4j / resilience4j

Resilience4j is a fault tolerance library designed for Java8 and functional programming
Apache License 2.0
9.77k stars 1.34k forks source link

Support `@CircuitBreaker` on suspend functions (including `suspend fun` fallback methods) in Spring Boot 2 #1539

Open efemoney opened 3 years ago

efemoney commented 3 years ago

Resilience4j version: 1.7.1 Java version: 16 kotlin version: 1.5.30

@CircuitBreaker does not work with bean suspend functions even when it boasts Kotlin Coroutines support.

First, FallbackMethod.create(...) will always fail to find the fallback method because of how kotlin inserts a kotlin.coroutines.Continuation<T> as the last parameter of suspend functions. This is illustrated below.

@Service class MyBean {

  @CircuitBreaker("breakerName", fallbackMethod = "aFallbackMethod")
  suspend fun aMethod(aParam: String): String { ... }

  suspend fun aFallbackMethod(theParam: String, error: Throwable): String { ... }
}

For the above bean the runtime method signatures are

aMethod(String, Continuation): Object & aFallbackMethod(String, Throwable, Continuation): Object

which is why the fallback method cannot be determined, because the throwable is not the last parameter in the fallback function.

Also, being a suspend function, its inherently asynchronous and needs to be explicitly handled (or wrapped somehow) inside of CircuitBreakerAspect to function correctly

RobWin commented 3 years ago

Hi, the Spring Boot module does not support Kotlin right now. You can only use resilience4j-kotlin directly. But feel free to create a PR to improve the Spring Boot Kotlin support.

efemoney commented 3 years ago

@RobWin Sounds good. I will open a PR soon for this.

vinmorel commented 2 years ago

Hi, on a similar note, does the micronaut module not support kotlin suspend functions as well? Having trouble on this side of things too.

AAverin commented 1 year ago

Was there a PR made and issue resolved? We would love to switch from CompletalbeFuture to suspend functions in our services.

RobWin commented 1 year ago

No

sangyongchoi commented 1 year ago

Hi, I have a question. If I use the resiliency4j-kotlin module, can I use it as below?

gradle

dependencies {
    implementation("org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j")
    implementation("io.github.resilience4j:resilience4j-kotlin:1.7.0")
}

kotlin

@CircuitBreaker(
    name = "myCircuitBreaker",
    fallbackMethod = "fallback"
)
suspend fun get() {
}

What I'm worried about is whether the Annotation and suspend function work normally when used together. If not, should I use it as below?

suspend fun get() {
     myCircuitBreaker.executeSuspendFunction {
     }
}
RobWin commented 1 year ago

Hi,

the annotations are not working with suspending functions yet.

sangyongchoi commented 1 year ago

@RobWin thank you for answer. not working when not add resilience4j-kotlin with exception that not exists method(Continuation) but seems to working when add resilience4j-kotlin dependency. If it's my misunderstanding, can you tell me why?

thank you :)

RobWin commented 1 year ago

resilience4j-kotlin only adds extension functions to decorate suspending functions. The module does not enhance the AOP/annotations capabilities of resilience4j-springboot2.

sangyongchoi commented 1 year ago

@RobWin thank you for answer. seems to working with suspend function in demo example repo it's my misunderstanding ?

added comment I guess annotation not working when fallback method is suspending function. seems to annotation working when fallback method is non suspending function.

gmmoreira commented 1 year ago

@sangyongchoi giving feedback, I just tested using latest Spring Boot 3 and Resilience4j Spring Boot 3 lib and the annotations doesn't work on suspend functions, using fallback methods didn't make any difference.

For now I'm just using decorateSuspend and executeSuspend functions from Kotlin addon lib.

mobin102 commented 5 months ago

@gmmoreira can you please write an example of how to use decorateSuspend and executeSuspend spring boot