now
Currently it is not possible to deactivate the TimeLimiter when using the circuitbreaker via org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory.
The org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JAutoConfiguration#resilience4jCircuitBreakerFactory defaults to a TimeLimiterRegistry which in turn always provides the default io.github.resilience4j.timelimiter.TimeLimiterConfig#timeoutDuration of 1s.
Later on, the org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreaker#run relies on the presence of a TimeLimiter since io.github.resilience4j.timelimiter.TimeLimiter#decorateFutureSupplier(io.github.resilience4j.timelimiter.TimeLimiter, java.util.function.Supplier<F>) is used to wrapp the invocation.
So there is no out-of-the-box-way to deactivate the TimeLimiter functionality of the spring-cloud-circuitbreaker via .yaml. If you want to use the circuitbreaker you get stuck with the TimeLimiter as well.
If there is already a proper way to use the spring-cloud circuitbreaker by making use of the CircuitBreakerFactory without the TimeLimiter, this feature request can be dropped immediately and no further reading is required. ;)
why
As an example, in a use case where a socket/port (with provided timeouts) gets opend within the circuitbreakers invocation, there is no need for a TimeLimiter on a higher level.
Additionally it can lead to serious resource leaks on certain operating systems to interrupt the calling Thread if a blocking I/O operation is running within the circuitbreakers invocation and somebody forgot to define a timeout on the I/O operation itself. Within this scenario the Thread could be interrupted but the I/O operation stays open/blocked, representing a possibly undetected resource leak.
workaround
As a workaround, we currently override the spring-cloud TimeLimiter with our own one which uses a timeout higher than the one used by the inner operation.
/**
* This configuration provides a custom {@link TimeLimiterRegistry}, used by <code>spring-cloud-circuitbreaker-resilience4j</code>.
* This configuration loaded conditionally, if <code>override-spring-cloud-timelimiter/code> is set to <code>true</code>.
*/
@Configuration
@ConditionalOnProperty(name = "override-spring-cloud-timelimiter")
public class SpringCloudResilience4JTimeLimiterConfig {
private static final Logger LOG = LoggerFactory.getLogger(SpringCloudResilience4JTimeLimiterConfig.class);
/**
* Retrieve a {@link TimeLimiterRegistry} which overrides the default timeout
* by using the socket's read timeout and multiplies it by two.
* <p>
* This is necessary since the sprint-cloud-resilience4j implementation does not permit using the circuit-breaker
* without using a time-limiter.
*
* @param timeoutMs the read timeout in milliseconds
* @return the customized {@link TimeLimiterRegistry}
* @see org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JAutoConfiguration
* @see org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreaker#run(Supplier, Function)
*/
@Bean
@Primary
public TimeLimiterRegistry timeLimiterRegistry(@Value("${resttemplate.readtimeout}") int timeoutMs) {
LOG.info("overriding spring-cloud circuitbreaker TimeLimiterRegistry");
return new InMemoryTimeLimiterRegistry(
TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofMillis(timeoutMs * 2L))
.cancelRunningFuture(false)
.build()
);
}
}
desired
It would be beautiful to either have a property provided which in turn would deactivate the TimeLimiter explicitely.
Otherwise it would be most logical to not activate/use the TimeLimiter within the Resilience4JCircuitBreaker if no TimeLimiter configuration is provided. But as a drawback, this would be a semantic API break which is probably not desired.
now
Currently it is not possible to deactivate the TimeLimiter when using the circuitbreaker via
org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory.The
org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JAutoConfiguration#resilience4jCircuitBreakerFactorydefaults to aTimeLimiterRegistrywhich in turn always provides the defaultio.github.resilience4j.timelimiter.TimeLimiterConfig#timeoutDurationof 1s.Later on, the
org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreaker#runrelies on the presence of aTimeLimitersinceio.github.resilience4j.timelimiter.TimeLimiter#decorateFutureSupplier(io.github.resilience4j.timelimiter.TimeLimiter, java.util.function.Supplier<F>)is used to wrapp the invocation.So there is no out-of-the-box-way to deactivate the TimeLimiter functionality of the
spring-cloud-circuitbreakervia.yaml. If you want to use the circuitbreaker you get stuck with the TimeLimiter as well.If there is already a proper way to use the spring-cloud circuitbreaker by making use of the
CircuitBreakerFactorywithout the TimeLimiter, this feature request can be dropped immediately and no further reading is required. ;)why
As an example, in a use case where a socket/port (with provided timeouts) gets opend within the circuitbreakers invocation, there is no need for a TimeLimiter on a higher level.
Additionally it can lead to serious resource leaks on certain operating systems to interrupt the calling Thread if a blocking I/O operation is running within the circuitbreakers invocation and somebody forgot to define a timeout on the I/O operation itself. Within this scenario the Thread could be interrupted but the I/O operation stays open/blocked, representing a possibly undetected resource leak.
workaround
As a workaround, we currently override the spring-cloud TimeLimiter with our own one which uses a timeout higher than the one used by the inner operation.
desired
It would be beautiful to either have a property provided which in turn would deactivate the TimeLimiter explicitely.
Otherwise it would be most logical to not activate/use the TimeLimiter within the
Resilience4JCircuitBreakerif no TimeLimiter configuration is provided. But as a drawback, this would be a semantic API break which is probably not desired.