This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch camel-4.10.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-4.10.x by this push:
new 5ea0702dfe1 CAMEL-22198: camel-resilience4j -
throwExceptionWhenHalfOpenOrOpenSta… (#18469)
5ea0702dfe1 is described below
commit 5ea0702dfe1317e02ff1ac9c5fce7c16bb7a03ad
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Jun 25 15:01:58 2025 +0200
CAMEL-22198: camel-resilience4j - throwExceptionWhenHalfOpenOrOpenSta…
(#18469)
* CAMEL-22198: camel-resilience4j - throwExceptionWhenHalfOpenOrOpenState
is not always thrown if in OPEN / HALF_OPEN state
---
.../catalog/models/resilience4jConfiguration.json | 2 +-
.../apache/camel/catalog/schemas/camel-spring.xsd | 4 ++-
.../resilience4j/ResilienceProcessor.java | 30 +++++++++++++---------
.../camel/model/resilience4jConfiguration.json | 2 +-
.../model/Resilience4jConfigurationCommon.java | 5 +++-
.../model/Resilience4jConfigurationDefinition.java | 5 +++-
.../dsl/yaml/deserializers/ModelDeserializers.java | 2 +-
.../generated/resources/schema/camelYamlDsl.json | 2 +-
8 files changed, 33 insertions(+), 19 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/resilience4jConfiguration.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/resilience4jConfiguration.json
index dc6cdad47b8..01482269073 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/resilience4jConfiguration.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/resilience4jConfiguration.json
@@ -17,7 +17,7 @@
"config": { "index": 2, "kind": "attribute", "displayName": "Config",
"group": "advanced", "label": "advanced", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "description": "Refers to an existing
io.github.resilience4j.circuitbreaker.CircuitBreakerConfig instance to lookup
and use from the registry." },
"failureRateThreshold": { "index": 3, "kind": "attribute", "displayName":
"Failure Rate Threshold", "group": "common", "required": false, "type":
"number", "javaType": "java.lang.Float", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "50", "description": "Configures the
failure rate threshold in percentage. If the failure rate is equal or greater
than the threshold the CircuitBreaker transitions to open and starts
short-circuiting calls. The threshold must [...]
"permittedNumberOfCallsInHalfOpenState": { "index": 4, "kind":
"attribute", "displayName": "Permitted Number Of Calls In Half Open State",
"group": "advanced", "label": "advanced", "required": false, "type": "integer",
"javaType": "java.lang.Integer", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "10", "description": "Configures the number of
permitted calls when the CircuitBreaker is half open. The size must be greater
than 0. Default size is 10." },
- "throwExceptionWhenHalfOpenOrOpenState": { "index": 5, "kind":
"attribute", "displayName": "Throw Exception When Half Open Or Open State",
"group": "common", "required": false, "type": "boolean", "javaType":
"java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether to throw
io.github.resilience4j.circuitbreaker.CallNotPermittedException when the call
is rejected due circuit breaker is half open or open." },
+ "throwExceptionWhenHalfOpenOrOpenState": { "index": 5, "kind":
"attribute", "displayName": "Throw Exception When Half Open Or Open State",
"group": "common", "required": false, "type": "boolean", "javaType":
"java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether to throw
io.github.resilience4j.circuitbreaker.CallNotPermittedException when the call
is rejected due circuit breaker is half open (and was not attempted [...]
"slidingWindowSize": { "index": 6, "kind": "attribute", "displayName":
"Sliding Window Size", "group": "common", "required": false, "type": "integer",
"javaType": "java.lang.Integer", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "100", "description": "Configures the size of
the sliding window which is used to record the outcome of calls when the
CircuitBreaker is closed. slidingWindowSize configures the size of the sliding
window. Sliding window can eithe [...]
"slidingWindowType": { "index": 7, "kind": "attribute", "displayName":
"Sliding Window Type", "group": "advanced", "label": "advanced", "required":
false, "type": "enum", "javaType": "java.lang.String", "enum": [ "TIME_BASED",
"COUNT_BASED" ], "deprecated": false, "autowired": false, "secret": false,
"defaultValue": "COUNT_BASED", "description": "Configures the type of the
sliding window which is used to record the outcome of calls when the
CircuitBreaker is closed. Sliding window ca [...]
"minimumNumberOfCalls": { "index": 8, "kind": "attribute", "displayName":
"Minimum Number Of Calls", "group": "common", "required": false, "type":
"integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "100", "description": "Configures the
minimum number of calls which are required (per sliding window period) before
the CircuitBreaker can calculate the error rate. For example, if
minimumNumberOfCalls is 10, then at least [...]
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
index 8346f8a4efa..9f63e787e34 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
@@ -4806,7 +4806,9 @@ size is 10. Default value: 10
<xs:documentation xml:lang="en">
<![CDATA[
Whether to throw
io.github.resilience4j.circuitbreaker.CallNotPermittedException when the call
is rejected due circuit
-breaker is half open or open. Default value: false
+breaker is half open (and was not attempted but rejected immediately) or open
(always rejected). This option is only in
+use when there is NOT a fallback configured on the circuit breaker. When there
is a fallback then the fallback is always
+executed and CallNotPermittedException is not thrown. Default value: false
]]>
</xs:documentation>
</xs:annotation>
diff --git
a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
index 8e9bbcf4e4b..bb0e8a1da0f 100644
---
a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
+++
b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
@@ -517,11 +517,16 @@ public class ResilienceProcessor extends
AsyncProcessorSupport
}
private Exchange processTask(Exchange exchange) {
+ String state = circuitBreaker.getState().name();
+
Exchange copy = null;
UnitOfWork uow = null;
Throwable cause;
try {
- LOG.debug("Running processor: {} with exchange: {}", processor,
exchange);
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Processing exchange: {} using circuit breaker
({}):{} with processor: {}",
+ exchange.getExchangeId(), state, id, processor);
+ }
// prepare a copy of exchange so downstream processors don't
// cause side-effects if they mutate the exchange
// in case timeout processing and continue with the fallback etc
@@ -627,12 +632,13 @@ public class ResilienceProcessor extends
AsyncProcessorSupport
@Override
public Exchange apply(Throwable throwable) {
+ String state = circuitBreaker.getState().name();
+
// check again if we should ignore or not record the throw
exception as a failure
if (ignorePredicate != null && ignorePredicate.test(throwable)) {
if (LOG.isTraceEnabled()) {
- LOG.trace("Processing exchange: {} recover task using
circuit breaker: {} ignored exception: {}",
- exchange.getExchangeId(),
- id, throwable);
+ LOG.trace("Processing exchange: {} recover task using
circuit breaker ({}):{} ignored exception: {}",
+ exchange.getExchangeId(), state, id, throwable);
}
// exception should be ignored
exchange.setProperty(ExchangePropertyKey.CIRCUIT_BREAKER_RESPONSE_SUCCESSFUL_EXECUTION,
false);
@@ -644,9 +650,8 @@ public class ResilienceProcessor extends
AsyncProcessorSupport
}
if (recordPredicate != null && !recordPredicate.test(throwable)) {
if (LOG.isTraceEnabled()) {
- LOG.trace("Processing exchange: {} recover task using
circuit breaker: {} success exception: {}",
- exchange.getExchangeId(),
- id, throwable);
+ LOG.trace("Processing exchange: {} recover task using
circuit breaker ({}):{} success exception: {}",
+ exchange.getExchangeId(), state, id, throwable);
}
// exception is a success
exchange.setProperty(ExchangePropertyKey.CIRCUIT_BREAKER_RESPONSE_SUCCESSFUL_EXECUTION,
true);
@@ -657,9 +662,8 @@ public class ResilienceProcessor extends
AsyncProcessorSupport
}
if (LOG.isTraceEnabled()) {
- LOG.trace("Processing exchange: {} recover task using circuit
breaker: {} failed exception: {}",
- exchange.getExchangeId(),
- id, throwable);
+ LOG.trace("Processing exchange: {} recover task using circuit
breaker ({}):{} failed exception: {}",
+ exchange.getExchangeId(), state, id, throwable);
}
if (fallback == null) {
@@ -721,10 +725,12 @@ public class ResilienceProcessor extends
AsyncProcessorSupport
exchange.getExchangeExtension().setRedeliveryExhausted(false);
// run the fallback processor
try {
- LOG.debug("Running fallback: {} with exchange: {}", fallback,
exchange);
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Processing exchange: {} using circuit breaker
({}):{} with fallback: {}",
+ exchange.getExchangeId(), state, id, fallback);
+ }
// process the fallback until its fully done
fallback.process(exchange);
- LOG.trace("Running fallback: {} with exchange: {} done",
fallback, exchange);
} catch (Throwable e) {
exchange.setException(e);
}
diff --git
a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/resilience4jConfiguration.json
b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/resilience4jConfiguration.json
index dc6cdad47b8..01482269073 100644
---
a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/resilience4jConfiguration.json
+++
b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/resilience4jConfiguration.json
@@ -17,7 +17,7 @@
"config": { "index": 2, "kind": "attribute", "displayName": "Config",
"group": "advanced", "label": "advanced", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "description": "Refers to an existing
io.github.resilience4j.circuitbreaker.CircuitBreakerConfig instance to lookup
and use from the registry." },
"failureRateThreshold": { "index": 3, "kind": "attribute", "displayName":
"Failure Rate Threshold", "group": "common", "required": false, "type":
"number", "javaType": "java.lang.Float", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "50", "description": "Configures the
failure rate threshold in percentage. If the failure rate is equal or greater
than the threshold the CircuitBreaker transitions to open and starts
short-circuiting calls. The threshold must [...]
"permittedNumberOfCallsInHalfOpenState": { "index": 4, "kind":
"attribute", "displayName": "Permitted Number Of Calls In Half Open State",
"group": "advanced", "label": "advanced", "required": false, "type": "integer",
"javaType": "java.lang.Integer", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "10", "description": "Configures the number of
permitted calls when the CircuitBreaker is half open. The size must be greater
than 0. Default size is 10." },
- "throwExceptionWhenHalfOpenOrOpenState": { "index": 5, "kind":
"attribute", "displayName": "Throw Exception When Half Open Or Open State",
"group": "common", "required": false, "type": "boolean", "javaType":
"java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether to throw
io.github.resilience4j.circuitbreaker.CallNotPermittedException when the call
is rejected due circuit breaker is half open or open." },
+ "throwExceptionWhenHalfOpenOrOpenState": { "index": 5, "kind":
"attribute", "displayName": "Throw Exception When Half Open Or Open State",
"group": "common", "required": false, "type": "boolean", "javaType":
"java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether to throw
io.github.resilience4j.circuitbreaker.CallNotPermittedException when the call
is rejected due circuit breaker is half open (and was not attempted [...]
"slidingWindowSize": { "index": 6, "kind": "attribute", "displayName":
"Sliding Window Size", "group": "common", "required": false, "type": "integer",
"javaType": "java.lang.Integer", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "100", "description": "Configures the size of
the sliding window which is used to record the outcome of calls when the
CircuitBreaker is closed. slidingWindowSize configures the size of the sliding
window. Sliding window can eithe [...]
"slidingWindowType": { "index": 7, "kind": "attribute", "displayName":
"Sliding Window Type", "group": "advanced", "label": "advanced", "required":
false, "type": "enum", "javaType": "java.lang.String", "enum": [ "TIME_BASED",
"COUNT_BASED" ], "deprecated": false, "autowired": false, "secret": false,
"defaultValue": "COUNT_BASED", "description": "Configures the type of the
sliding window which is used to record the outcome of calls when the
CircuitBreaker is closed. Sliding window ca [...]
"minimumNumberOfCalls": { "index": 8, "kind": "attribute", "displayName":
"Minimum Number Of Calls", "group": "common", "required": false, "type":
"integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "100", "description": "Configures the
minimum number of calls which are required (per sliding window period) before
the CircuitBreaker can calculate the error rate. For example, if
minimumNumberOfCalls is 10, then at least [...]
diff --git
a/core/camel-core-model/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
b/core/camel-core-model/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
index 01164035d00..81022019b05 100644
---
a/core/camel-core-model/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
+++
b/core/camel-core-model/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
@@ -189,7 +189,10 @@ public class Resilience4jConfigurationCommon extends
IdentifiedType {
/**
* Whether to throw
io.github.resilience4j.circuitbreaker.CallNotPermittedException when the call
is rejected due
- * circuit breaker is half open or open.
+ * circuit breaker is half open (and was not attempted but rejected
immediately) or open (always rejected).
+ *
+ * This option is only in use when there is NOT a fallback configured on
the circuit breaker. When there is a
+ * fallback then the fallback is always executed and
CallNotPermittedException is not thrown.
*/
public void setThrowExceptionWhenHalfOpenOrOpenState(String
throwExceptionWhenHalfOpenOrOpenState) {
this.throwExceptionWhenHalfOpenOrOpenState =
throwExceptionWhenHalfOpenOrOpenState;
diff --git
a/core/camel-core-model/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
b/core/camel-core-model/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
index 71481510fbc..1255c5c79ab 100644
---
a/core/camel-core-model/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
+++
b/core/camel-core-model/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
@@ -99,7 +99,10 @@ public class Resilience4jConfigurationDefinition extends
Resilience4jConfigurati
/**
* Whether to throw
io.github.resilience4j.circuitbreaker.CallNotPermittedException when the call
is rejected due
- * circuit breaker is half open or open.
+ * circuit breaker is half open (and was not attempted but rejected
immediately) or open (always rejected).
+ *
+ * This option is only in use when there is NOT a fallback configured on
the circuit breaker. When there is a
+ * fallback then the fallback is always executed and
CallNotPermittedException is not thrown.
*/
public Resilience4jConfigurationDefinition
throwExceptionWhenHalfOpenOrOpenState(
boolean throwExceptionWhenHalfOpenOrOpenState) {
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
index de2ff3fe62a..da8316b5f64 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
@@ -13935,7 +13935,7 @@ public final class ModelDeserializers extends
YamlDeserializerSupport {
@YamlProperty(name = "slidingWindowType", type =
"enum:TIME_BASED,COUNT_BASED", defaultValue = "COUNT_BASED", description =
"Configures the type of the sliding window which is used to record the outcome
of calls when the CircuitBreaker is closed. Sliding window can either be
count-based or time-based. If slidingWindowType is COUNT_BASED, the last
slidingWindowSize calls are recorded and aggregated. If slidingWindowType is
TIME_BASED, the calls of the last slidingWindo [...]
@YamlProperty(name = "slowCallDurationThreshold", type =
"number", defaultValue = "60", description = "Configures the duration threshold
(seconds) above which calls are considered as slow and increase the slow calls
percentage. Default value is 60 seconds.", displayName = "Slow Call Duration
Threshold"),
@YamlProperty(name = "slowCallRateThreshold", type =
"number", defaultValue = "100", description = "Configures a threshold in
percentage. The CircuitBreaker considers a call as slow when the call duration
is greater than slowCallDurationThreshold Duration. When the percentage of slow
calls is equal or greater the threshold, the CircuitBreaker transitions to open
and starts short-circuiting calls. The threshold must be greater than 0 and not
greater than 100. Default v [...]
- @YamlProperty(name =
"throwExceptionWhenHalfOpenOrOpenState", type = "boolean", description =
"Whether to throw
io.github.resilience4j.circuitbreaker.CallNotPermittedException when the call
is rejected due circuit breaker is half open or open.", displayName = "Throw
Exception When Half Open Or Open State"),
+ @YamlProperty(name =
"throwExceptionWhenHalfOpenOrOpenState", type = "boolean", description =
"Whether to throw
io.github.resilience4j.circuitbreaker.CallNotPermittedException when the call
is rejected due circuit breaker is half open (and was not attempted but
rejected immediately) or open (always rejected). This option is only in use
when there is NOT a fallback configured on the circuit breaker. When there is a
fallback then the fallback is always executed and Call [...]
@YamlProperty(name = "timeoutCancelRunningFuture", type =
"boolean", description = "Configures whether cancel is called on the running
future. Defaults to true.", displayName = "Timeout Cancel Running Future"),
@YamlProperty(name = "timeoutDuration", type = "number",
defaultValue = "1000", description = "Configures the thread execution timeout.
Default value is 1 second.", displayName = "Timeout Duration"),
@YamlProperty(name = "timeoutEnabled", type = "boolean",
description = "Whether timeout is enabled or not on the circuit breaker.
Default is false.", displayName = "Timeout Enabled"),
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
index aba98d0ea64..2ce877a8c47 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
@@ -5120,7 +5120,7 @@
"throwExceptionWhenHalfOpenOrOpenState" : {
"type" : "boolean",
"title" : "Throw Exception When Half Open Or Open State",
- "description" : "Whether to throw
io.github.resilience4j.circuitbreaker.CallNotPermittedException when the call
is rejected due circuit breaker is half open or open."
+ "description" : "Whether to throw
io.github.resilience4j.circuitbreaker.CallNotPermittedException when the call
is rejected due circuit breaker is half open (and was not attempted but
rejected immediately) or open (always rejected). This option is only in use
when there is NOT a fallback configured on the circuit breaker. When there is a
fallback then the fallback is always executed and CallNotPermittedException is
not thrown."
},
"timeoutCancelRunningFuture" : {
"type" : "boolean",