diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json index 144a7868822fc..1acde96827c6f 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json @@ -347,24 +347,27 @@ { "name": "camel.opentelemetry2.traceProcessors", "required": false, "description": "Setting this to true will create new telemetry spans for each Camel custom Processors. Use the excludePattern property to filter out Processors.", "sourceType": "org.apache.camel.main.Otel2ConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false }, { "name": "camel.resilience4j.automaticTransitionFromOpenToHalfOpenEnabled", "required": false, "description": "Enables automatic transition from OPEN to HALF_OPEN state once the waitDurationInOpenState has passed.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": false, "secret": false }, { "name": "camel.resilience4j.bulkheadEnabled", "required": false, "description": "Whether bulkhead is enabled or not on the circuit breaker.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": false, "secret": false }, + { "name": "camel.resilience4j.bulkheadFairCallHandlingEnabled", "required": false, "description": "Configures whether the bulkhead uses a fair calling strategy. When enabled (default), a fair strategy guarantees the order of incoming requests (FIFO). When disabled, no ordering is guaranteed and may improve throughput.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": true, "secret": false }, { "name": "camel.resilience4j.bulkheadMaxConcurrentCalls", "required": false, "description": "Configures the max amount of concurrent calls the bulkhead will support.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "secret": false }, - { "name": "camel.resilience4j.bulkheadMaxWaitDuration", "required": false, "description": "Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. If bulkhead has space available, entry is guaranteed and immediate. If bulkhead is full, calling threads will contest for space, if it becomes available. maxWaitDuration can be set to 0. Note: for threads running on an event-loop or equivalent (rx computation pool, etc), setting maxWaitDuration to 0 is highly recommended. Blocking an event-loop thread will most likely have a negative effect on application throughput.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "secret": false }, + { "name": "camel.resilience4j.bulkheadMaxWaitDuration", "required": false, "description": "Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. Accepts Camel duration expressions (e.g. 500ms, 1s) or millisecond values. Default is 0 (no waiting).", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.resilience4j.circuitBreaker", "required": false, "description": "Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreaker instance to lookup and use from the registry. When using this, then any other circuit breaker options are not in use.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.resilience4j.config", "required": false, "description": "Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreakerConfig instance to lookup and use from the registry.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.resilience4j.failureRateThreshold", "required": false, "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 be greater than 0 and not greater than 100. Default value is 50 percentage.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "number", "javaType": "java.lang.Float", "defaultValue": "50", "secret": false }, + { "name": "camel.resilience4j.maxWaitDurationInHalfOpenState", "required": false, "description": "Configures the maximum wait duration which controls how long the CircuitBreaker should stay in Half Open state, before it switches to open. Value 0 means circuit breaker will wait in half open state until all permitted calls have been completed. Accepts Camel duration expressions (e.g. 10s, 1m) or millisecond values.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "0", "secret": false }, { "name": "camel.resilience4j.micrometerEnabled", "required": false, "description": "Whether to enable collecting statistics using Micrometer. This requires adding camel-resilience4j-micrometer JAR to the classpath.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": false, "secret": false }, { "name": "camel.resilience4j.minimumNumberOfCalls", "required": false, "description": "Configures 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 10 calls must be recorded, before the failure rate can be calculated. If only 9 calls have been recorded the CircuitBreaker will not transition to open even if all 9 calls have failed. Default minimumNumberOfCalls is 100", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "defaultValue": 100, "secret": false }, { "name": "camel.resilience4j.permittedNumberOfCallsInHalfOpenState", "required": false, "description": "Configures the number of permitted calls when the CircuitBreaker is half open. The size must be greater than 0. Default size is 10.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "defaultValue": 10, "secret": false }, { "name": "camel.resilience4j.slidingWindowSize", "required": false, "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 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 slidingWindowSize seconds are recorded and aggregated. The slidingWindowSize must be greater than 0. The minimumNumberOfCalls must be greater than 0. If the slidingWindowType is COUNT_BASED, the minimumNumberOfCalls cannot be greater than slidingWindowSize . If the slidingWindowType is TIME_BASED, you can pick whatever you want. Default slidingWindowSize is 100.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "defaultValue": 100, "secret": false }, + { "name": "camel.resilience4j.slidingWindowSynchronizationStrategy", "required": false, "description": "Configures the synchronization strategy for the sliding window. LOCK_FREE uses a CAS-based lock-free algorithm for better performance under high concurrency. SYNCHRONIZED uses blocking locks with lower memory allocation.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "enum", "javaType": "java.lang.String", "defaultValue": "SYNCHRONIZED", "secret": false, "enum": [ "LOCK_FREE", "SYNCHRONIZED" ] }, { "name": "camel.resilience4j.slidingWindowType", "required": false, "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 slidingWindowSize seconds are recorded and aggregated. Default slidingWindowType is COUNT_BASED.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "enum", "javaType": "java.lang.String", "defaultValue": "COUNT_BASED", "secret": false, "enum": [ "COUNT_BASED", "TIME_BASED" ] }, - { "name": "camel.resilience4j.slowCallDurationThreshold", "required": false, "description": "Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls percentage. Default value is 60 seconds.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "defaultValue": 60, "secret": false }, + { "name": "camel.resilience4j.slowCallDurationThreshold", "required": false, "description": "Configures the duration threshold above which calls are considered as slow and increase the slow calls percentage. Accepts Camel duration expressions (e.g. 60s, 1m) or millisecond values. Default value is 60 seconds.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "60s", "secret": false }, { "name": "camel.resilience4j.slowCallRateThreshold", "required": false, "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 value is 100 percentage which means that all recorded calls must be slower than slowCallDurationThreshold.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "number", "javaType": "java.lang.Float", "defaultValue": "100", "secret": false }, { "name": "camel.resilience4j.throwExceptionWhenHalfOpenOrOpenState", "required": false, "description": "Whether to throw io.github.resilience4j.circuitbreaker.CallNotPermittedException when the call is rejected due circuit breaker is half open or open.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": false, "secret": false }, { "name": "camel.resilience4j.timeoutCancelRunningFuture", "required": false, "description": "Configures whether cancel is called on the running future. Defaults to true.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": true, "secret": false }, - { "name": "camel.resilience4j.timeoutDuration", "required": false, "description": "Configures the thread execution timeout (millis). Default value is 1000 millis (1 second).", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "defaultValue": 1000, "secret": false }, + { "name": "camel.resilience4j.timeoutDuration", "required": false, "description": "Configures the thread execution timeout. Accepts Camel duration expressions (e.g. 1s, 500ms) or millisecond values. Default value is 1000 millis (1 second).", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "1000", "secret": false }, { "name": "camel.resilience4j.timeoutEnabled", "required": false, "description": "Whether timeout is enabled or not on the circuit breaker. Default is false.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": false, "secret": false }, { "name": "camel.resilience4j.timeoutExecutorService", "required": false, "description": "References to a custom thread pool to use when timeout is enabled (uses ForkJoinPool#commonPool() by default)", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "string", "javaType": "java.lang.String", "secret": false }, - { "name": "camel.resilience4j.waitDurationInOpenState", "required": false, "description": "Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it switches to half open. Default value is 60 seconds.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "defaultValue": 60, "secret": false }, + { "name": "camel.resilience4j.waitDurationInOpenState", "required": false, "description": "Configures the wait duration which specifies how long the CircuitBreaker should stay open, before it switches to half open. Accepts Camel duration expressions (e.g. 60s, 1m) or millisecond values. Default value is 60 seconds.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "60s", "secret": false }, { "name": "camel.resilience4j.writableStackTraceEnabled", "required": false, "description": "Enables writable stack traces. When set to false, Exception.getStackTrace returns a zero length array. This may be used to reduce log spam when the circuit breaker is open as the cause of the exceptions is already known (the circuit breaker is short-circuiting calls).", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": false, "secret": false }, { "name": "camel.rest.apiComponent", "required": false, "description": "Sets the name of the Camel component to use as the REST API (such as swagger or openapi)", "sourceType": "org.apache.camel.spi.RestConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.rest.apiContextPath", "required": false, "description": "Sets a leading API context-path the REST API services will be using. This can be used when using components such as camel-servlet where the deployed web application is deployed using a context-path.", "sourceType": "org.apache.camel.spi.RestConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/onFallback.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/onFallback.json index fcc732c0c3631..115d7228f5889 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/onFallback.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/onFallback.json @@ -16,7 +16,7 @@ "id": { "index": 0, "kind": "attribute", "displayName": "Id", "group": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The id of this node" }, "note": { "index": 1, "kind": "attribute", "displayName": "Note", "group": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The note for this node" }, "description": { "index": 2, "kind": "attribute", "displayName": "Description", "group": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The description for this node" }, - "fallbackViaNetwork": { "index": 3, "kind": "attribute", "displayName": "Fallback Via Network", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the fallback goes over the network. If so, the fallback is executed on a separate thread-pool to avoid exhausting the main thread-pool." }, + "fallbackViaNetwork": { "index": 3, "kind": "attribute", "displayName": "Fallback Via Network", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": true, "deprecationNote": "Not supported by any circuit breaker implementation.", "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the fallback goes over the network. If so, the fallback is executed on a separate thread-pool to avoid exhausting the main thread-pool." }, "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "group": "common", "required": true, "type": "array", "javaType": "java.util.List>", "oneOf": [ "a2aSubTask", "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onException", "pausable", "pipeline", "policy", "poll", "pollEnrich", "process", "recipientList", "removeHeader", "removeHeaders", "removeProperties", "removeProperty", "removeVariable", "resequence", "resumable", "rollback", "routingSlip", "saga", "sample", "script", "setBody", "setExchangePattern", "setHeader", "setHeaders", "setProperty", "setVariable", "setVariables", "sort", "split", "step", "stop", "threads", "throttle", "throwException", "to", "toD", "tokenizer", "transacted", "transform", "transformDataType", "unmarshal", "validate", "wireTap" ], "deprecated": false, "autowired": false, "secret": false } } } 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 e2ee2d25745bb..9b1452808a393 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 @@ -20,21 +20,24 @@ "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 because the circuit breaker is half open or open." }, "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. Sliding window can either be count-based or time-based." }, "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 can either be count-based or time-based." }, - "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." }, - "writableStackTraceEnabled": { "index": 9, "kind": "attribute", "displayName": "Writable Stack Trace Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Enables writable stack traces. When set to false, Exception.getStackTrace returns a zero length array. This may be used to reduce log spam when the circuit breaker is open." }, - "waitDurationInOpenState": { "index": 10, "kind": "attribute", "displayName": "Wait Duration In Open State", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 60, "description": "Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it switches to half open." }, - "automaticTransitionFromOpenToHalfOpenEnabled": { "index": 11, "kind": "attribute", "displayName": "Automatic Transition From Open To Half Open Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enables automatic transition from OPEN to HALF_OPEN state once the waitDurationInOpenState has passed." }, - "slowCallRateThreshold": { "index": 12, "kind": "attribute", "displayName": "Slow Call Rate Threshold", "group": "advanced", "label": "advanced", "required": false, "type": "number", "javaType": "java.lang.Float", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "100", "description": "Configures a threshold in percentage. The CircuitBreaker considers a call as slow when the call duration is greater than slowCallDurationThreshold. When the percentage of slow calls is equal or greater the threshold, the CircuitBreaker transitions to open and starts short-circuiting calls." }, - "slowCallDurationThreshold": { "index": 13, "kind": "attribute", "displayName": "Slow Call Duration Threshold", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 60, "description": "Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls percentage." }, - "bulkheadEnabled": { "index": 14, "kind": "attribute", "displayName": "Bulkhead Enabled", "group": "common", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether bulkhead is enabled or not on the circuit breaker." }, - "bulkheadMaxConcurrentCalls": { "index": 15, "kind": "attribute", "displayName": "Bulkhead Max Concurrent Calls", "group": "common", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 25, "description": "Configures the max amount of concurrent calls the bulkhead will support." }, - "bulkheadMaxWaitDuration": { "index": 16, "kind": "attribute", "displayName": "Bulkhead Max Wait Duration", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 0, "description": "Configures a maximum amount of time which the calling thread will wait to enter the bulkhead." }, - "timeoutEnabled": { "index": 17, "kind": "attribute", "displayName": "Timeout Enabled", "group": "common", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether timeout is enabled or not on the circuit breaker." }, - "timeoutExecutorService": { "index": 18, "kind": "attribute", "displayName": "Timeout Executor Service", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.util.concurrent.ExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "References to a custom thread pool to use when timeout is enabled (uses ForkJoinPool.commonPool() by default)." }, - "timeoutDuration": { "index": 19, "kind": "attribute", "displayName": "Timeout Duration", "group": "common", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1000, "description": "Configures the thread execution timeout. Default value is 1 second." }, - "timeoutCancelRunningFuture": { "index": 20, "kind": "attribute", "displayName": "Timeout Cancel Running Future", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Configures whether cancel is called on the running future. Defaults to true." }, - "micrometerEnabled": { "index": 21, "kind": "attribute", "displayName": "Micrometer Enabled", "group": "common", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to enable collecting statistics using Micrometer. This requires adding camel-resilience4j-micrometer JAR to the classpath." }, - "recordException": { "index": 22, "kind": "element", "displayName": "Record Exception", "group": "advanced", "label": "advanced", "required": false, "type": "array", "javaType": "java.util.List", "deprecated": false, "autowired": false, "secret": false, "description": "Configure a list of exceptions that are recorded as a failure and thus increase the failure rate. Any exception matching or inheriting from one of the list counts as a failure, unless explicitly ignored via ignoreExceptions." }, - "ignoreException": { "index": 23, "kind": "element", "displayName": "Ignore Exception", "group": "advanced", "label": "advanced", "required": false, "type": "array", "javaType": "java.util.List", "deprecated": false, "autowired": false, "secret": false, "description": "Configure a list of exceptions that are ignored and neither count as a failure nor success. Any exception matching or inheriting from one of the list will not count as a failure nor success, even if the exception is part of recordExceptions." } + "slidingWindowSynchronizationStrategy": { "index": 8, "kind": "attribute", "displayName": "Sliding Window Synchronization Strategy", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "LOCK_FREE", "SYNCHRONIZED" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "SYNCHRONIZED", "description": "Configures the synchronization strategy for the sliding window. LOCK_FREE uses a CAS-based lock-free algorithm for better performance under high concurrency. SYNCHRONIZED uses blocking locks with lower memory allocation." }, + "minimumNumberOfCalls": { "index": 9, "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." }, + "writableStackTraceEnabled": { "index": 10, "kind": "attribute", "displayName": "Writable Stack Trace Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Enables writable stack traces. When set to false, Exception.getStackTrace returns a zero length array. This may be used to reduce log spam when the circuit breaker is open." }, + "waitDurationInOpenState": { "index": 11, "kind": "attribute", "displayName": "Wait Duration In Open State", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "60000", "description": "Configures the wait duration which specifies how long the CircuitBreaker should stay open, before it switches to half open. The default is 60 seconds." }, + "automaticTransitionFromOpenToHalfOpenEnabled": { "index": 12, "kind": "attribute", "displayName": "Automatic Transition From Open To Half Open Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enables automatic transition from OPEN to HALF_OPEN state once the waitDurationInOpenState has passed." }, + "maxWaitDurationInHalfOpenState": { "index": 13, "kind": "attribute", "displayName": "Max Wait Duration In Half Open State", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "0", "description": "Configures the maximum wait duration which controls how long the CircuitBreaker should stay in Half Open state, before it switches to open. Value 0 means circuit breaker will wait in half open state until all permitted calls have been completed." }, + "slowCallRateThreshold": { "index": 14, "kind": "attribute", "displayName": "Slow Call Rate Threshold", "group": "advanced", "label": "advanced", "required": false, "type": "number", "javaType": "java.lang.Float", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "100", "description": "Configures a threshold in percentage. The CircuitBreaker considers a call as slow when the call duration is greater than slowCallDurationThreshold. When the percentage of slow calls is equal or greater the threshold, the CircuitBreaker transitions to open and starts short-circuiting calls." }, + "slowCallDurationThreshold": { "index": 15, "kind": "attribute", "displayName": "Slow Call Duration Threshold", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "60000", "description": "Configures the duration threshold above which calls are considered as slow and increase the slow calls percentage. The default is 60 seconds." }, + "bulkheadEnabled": { "index": 16, "kind": "attribute", "displayName": "Bulkhead Enabled", "group": "common", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether bulkhead is enabled or not on the circuit breaker." }, + "bulkheadMaxConcurrentCalls": { "index": 17, "kind": "attribute", "displayName": "Bulkhead Max Concurrent Calls", "group": "common", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 25, "description": "Configures the max amount of concurrent calls the bulkhead will support." }, + "bulkheadMaxWaitDuration": { "index": 18, "kind": "attribute", "displayName": "Bulkhead Max Wait Duration", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "0", "description": "Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. The default is 0 (no waiting)." }, + "bulkheadFairCallHandlingEnabled": { "index": 19, "kind": "attribute", "displayName": "Bulkhead Fair Call Handling Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Configures whether the bulkhead uses a fair calling strategy. When enabled (default), a fair strategy guarantees the order of incoming requests (FIFO). When disabled, no ordering is guaranteed and may improve throughput." }, + "timeoutEnabled": { "index": 20, "kind": "attribute", "displayName": "Timeout Enabled", "group": "common", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether timeout is enabled or not on the circuit breaker." }, + "timeoutExecutorService": { "index": 21, "kind": "attribute", "displayName": "Timeout Executor Service", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.util.concurrent.ExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "References to a custom thread pool to use when timeout is enabled (uses ForkJoinPool.commonPool() by default)." }, + "timeoutDuration": { "index": 22, "kind": "attribute", "displayName": "Timeout Duration", "group": "common", "required": false, "type": "duration", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "1000", "description": "Configures the thread execution timeout. Default value is 1 second." }, + "timeoutCancelRunningFuture": { "index": 23, "kind": "attribute", "displayName": "Timeout Cancel Running Future", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Configures whether cancel is called on the running future. Defaults to true." }, + "micrometerEnabled": { "index": 24, "kind": "attribute", "displayName": "Micrometer Enabled", "group": "common", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to enable collecting statistics using Micrometer for all circuit breaker instances. This is a global setting (configure via camel.resilience4j.micrometerEnabled=true) and requires adding camel-resilience4j-micrometer JAR to the classpath." }, + "recordException": { "index": 25, "kind": "element", "displayName": "Record Exception", "group": "advanced", "label": "advanced", "required": false, "type": "array", "javaType": "java.util.List", "deprecated": false, "autowired": false, "secret": false, "description": "Configure a list of exceptions that are recorded as a failure and thus increase the failure rate. Any exception matching or inheriting from one of the list counts as a failure, unless explicitly ignored via ignoreExceptions." }, + "ignoreException": { "index": 26, "kind": "element", "displayName": "Ignore Exception", "group": "advanced", "label": "advanced", "required": false, "type": "array", "javaType": "java.util.List", "deprecated": false, "autowired": false, "secret": false, "description": "Configure a list of exceptions that are ignored and neither count as a failure nor success. Any exception matching or inheriting from one of the list will not count as a failure nor success, even if the exception is part of recordExceptions." } } } 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 a1b529fd3603e..6e46cb1ed12d3 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 @@ -4450,6 +4450,17 @@ closed. Sliding window can either be count-based or time-based. Default value: 1 + + + + + + + @@ -4478,8 +4489,8 @@ to reduce log spam when the circuit breaker is open. Default value: true @@ -4490,6 +4501,17 @@ switches to half open. Default value: 60 + + + + + + + @@ -4509,8 +4531,8 @@ transitions to open and starts short-circuiting calls. Default value: 100 @@ -4537,7 +4559,19 @@ Configures the max amount of concurrent calls the bulkhead will support. Default + + + + + + + @@ -4582,7 +4616,8 @@ Configures whether cancel is called on the running future. Defaults to true. Def @@ -4797,8 +4832,8 @@ References a custom thread pool to use when offloading a guarded action to anoth diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-xml-io.xsd b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-xml-io.xsd index f4e0045b81448..54833296f891f 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-xml-io.xsd +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-xml-io.xsd @@ -3560,6 +3560,17 @@ closed. Sliding window can either be count-based or time-based. Default value: 1 + + + + + + + @@ -3588,8 +3599,8 @@ to reduce log spam when the circuit breaker is open. Default value: true @@ -3600,6 +3611,17 @@ switches to half open. Default value: 60 + + + + + + + @@ -3619,8 +3641,8 @@ transitions to open and starts short-circuiting calls. Default value: 100 @@ -3647,7 +3669,19 @@ Configures the max amount of concurrent calls the bulkhead will support. Default + + + + + + + @@ -3692,7 +3726,8 @@ Configures whether cancel is called on the running future. Defaults to true. Def @@ -3919,8 +3954,8 @@ References a custom thread pool to use when offloading a guarded action to anoth diff --git a/components/camel-resilience4j/pom.xml b/components/camel-resilience4j/pom.xml index 4aa1ff1422d69..f85217cf33b4c 100644 --- a/components/camel-resilience4j/pom.xml +++ b/components/camel-resilience4j/pom.xml @@ -57,12 +57,6 @@ io.github.resilience4j resilience4j-circuitbreaker ${resilience4j-version} - - - io.vavr - vavr - - io.github.resilience4j @@ -74,17 +68,6 @@ resilience4j-timelimiter ${resilience4j-version} - - io.vavr - vavr - ${vavr-version} - - - io.vavr - vavr-match - ${vavr-version} - - org.apache.camel 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 278487ffb3cbb..eade717315737 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 @@ -39,7 +39,6 @@ import io.github.resilience4j.timelimiter.TimeLimiter; import io.github.resilience4j.timelimiter.TimeLimiterConfig; import io.github.resilience4j.timelimiter.TimeLimiterRegistry; -import io.vavr.control.Try; import org.apache.camel.AsyncCallback; import org.apache.camel.CamelContext; import org.apache.camel.CamelContextAware; @@ -548,10 +547,12 @@ public boolean process(Exchange exchange, AsyncCallback callback) { if (LOG.isTraceEnabled()) { LOG.trace("Processing exchange: {} using circuit breaker: {}", exchange.getExchangeId(), id); } - Try.ofCallable(callable) - .andThen(this::successState) - .recover(fallbackTask) - .get(); + try { + Exchange result = callable.call(); + successState(result); + } catch (Exception e) { + fallbackTask.apply(e); + } } catch (Exception e) { exchange.setException(e); } finally { @@ -788,6 +789,9 @@ public Exchange apply(Throwable throwable) { exchange.setProperty(ExchangePropertyKey.CIRCUIT_BREAKER_RESPONSE_SUCCESSFUL_EXECUTION, false); exchange.setProperty(ExchangePropertyKey.CIRCUIT_BREAKER_RESPONSE_FROM_FALLBACK, true); exchange.setProperty(ExchangePropertyKey.CIRCUIT_BREAKER_RESPONSE_SHORT_CIRCUITED, true); + if (throwable instanceof TimeoutException) { + exchange.setProperty(ExchangePropertyKey.CIRCUIT_BREAKER_RESPONSE_TIMED_OUT, true); + } // store the last to endpoint as the failure endpoint if (exchange.getProperty(ExchangePropertyKey.FAILURE_ENDPOINT) == null) { @@ -796,7 +800,11 @@ public Exchange apply(Throwable throwable) { } // give the rest of the pipeline another chance exchange.setProperty(ExchangePropertyKey.EXCEPTION_HANDLED, true); - exchange.setProperty(ExchangePropertyKey.EXCEPTION_CAUGHT, exchange.getException()); + // use the guard-level throwable for EXCEPTION_CAUGHT since the exchange + // may not have the exception set (e.g. on timeout the exception is thrown + // by the TimeLimiter on the caller thread, not set on the exchange) + Throwable caught = exchange.getException() != null ? exchange.getException() : throwable; + exchange.setProperty(ExchangePropertyKey.EXCEPTION_CAUGHT, caught); exchange.setRouteStop(false); exchange.setException(null); // and we should not be regarded as exhausted as we are in a try .. diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java index d0f386e95ae28..f198261372d23 100644 --- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java +++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java @@ -151,14 +151,23 @@ private CircuitBreakerConfig configureCircuitBreaker(Resilience4jConfigurationCo if (config.getSlidingWindowType() != null) { builder.slidingWindowType(CircuitBreakerConfig.SlidingWindowType.valueOf(config.getSlidingWindowType())); } + if (config.getSlidingWindowSynchronizationStrategy() != null) { + builder.slidingWindowSynchronizationStrategy( + CircuitBreakerConfig.SlidingWindowSynchronizationStrategy + .valueOf(config.getSlidingWindowSynchronizationStrategy())); + } if (config.getSlowCallDurationThreshold() != null) { - builder.slowCallDurationThreshold(Duration.ofSeconds(parseLong(config.getSlowCallDurationThreshold()))); + builder.slowCallDurationThreshold(Duration.ofMillis(parseDuration(config.getSlowCallDurationThreshold()))); } if (config.getSlowCallRateThreshold() != null) { builder.slowCallRateThreshold(parseFloat(config.getSlowCallRateThreshold())); } if (config.getWaitDurationInOpenState() != null) { - builder.waitDurationInOpenState(Duration.ofSeconds(parseLong(config.getWaitDurationInOpenState()))); + builder.waitDurationInOpenState(Duration.ofMillis(parseDuration(config.getWaitDurationInOpenState()))); + } + if (config.getMaxWaitDurationInHalfOpenState() != null) { + builder.maxWaitDurationInHalfOpenState( + Duration.ofMillis(parseDuration(config.getMaxWaitDurationInHalfOpenState()))); } if (config.getWritableStackTraceEnabled() != null) { builder.writableStackTraceEnabled(parseBoolean(config.getWritableStackTraceEnabled())); @@ -182,13 +191,16 @@ private BulkheadConfig configureBulkHead(Resilience4jConfigurationCommon config) builder.maxConcurrentCalls(parseInt(config.getBulkheadMaxConcurrentCalls())); } if (config.getBulkheadMaxWaitDuration() != null) { - long duration = parseLong(config.getBulkheadMaxWaitDuration()); + long duration = parseDuration(config.getBulkheadMaxWaitDuration()); if (duration <= 0) { builder.maxWaitDuration(Duration.ZERO); } else { builder.maxWaitDuration(Duration.ofMillis(duration)); } } + if (config.getBulkheadFairCallHandlingEnabled() != null) { + builder.fairCallHandlingStrategyEnabled(parseBoolean(config.getBulkheadFairCallHandlingEnabled())); + } return builder.build(); } @@ -199,7 +211,7 @@ private TimeLimiterConfig configureTimeLimiter(Resilience4jConfigurationCommon c TimeLimiterConfig.Builder builder = TimeLimiterConfig.custom(); if (config.getTimeoutDuration() != null) { - builder.timeoutDuration(Duration.ofMillis(parseLong(config.getTimeoutDuration()))); + builder.timeoutDuration(Duration.ofMillis(parseDuration(config.getTimeoutDuration()))); } if (config.getTimeoutCancelRunningFuture() != null) { builder.cancelRunningFuture(parseBoolean(config.getTimeoutCancelRunningFuture())); diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceNewOptionsTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceNewOptionsTest.java new file mode 100644 index 0000000000000..3e94ef444d2fc --- /dev/null +++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceNewOptionsTest.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.resilience4j; + +import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig; +import org.apache.camel.Navigate; +import org.apache.camel.Processor; +import org.apache.camel.Route; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spi.CircuitBreakerConstants; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class ResilienceNewOptionsTest extends CamelTestSupport { + + @Test + public void testSlidingWindowSynchronizationStrategy() throws Exception { + getMockEndpoint("mock:result").expectedBodiesReceived("Bye World"); + getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, true); + + template.sendBody("direct:start", "Hello World"); + + MockEndpoint.assertIsSatisfied(context); + + ResilienceProcessor processor = findResilienceProcessor(); + assertNotNull(processor); + + CircuitBreakerConfig config = processor.getCircuitBreaker().getCircuitBreakerConfig(); + assertEquals(CircuitBreakerConfig.SlidingWindowSynchronizationStrategy.LOCK_FREE, + config.getSlidingWindowSynchronizationStrategy()); + } + + @Test + public void testMaxWaitDurationInHalfOpenState() throws Exception { + getMockEndpoint("mock:result2").expectedBodiesReceived("Bye World"); + + template.sendBody("direct:start2", "Hello World"); + + MockEndpoint.assertIsSatisfied(context); + + ResilienceProcessor processor = findResilienceProcessor("start2"); + assertNotNull(processor); + + CircuitBreakerConfig config = processor.getCircuitBreaker().getCircuitBreakerConfig(); + assertEquals(30_000, config.getMaxWaitDurationInHalfOpenState().toMillis()); + } + + @Test + public void testBulkheadFairCallHandlingDisabled() throws Exception { + getMockEndpoint("mock:result3").expectedBodiesReceived("Bye World"); + + template.sendBody("direct:start3", "Hello World"); + + MockEndpoint.assertIsSatisfied(context); + + ResilienceProcessor processor = findResilienceProcessor("start3"); + assertNotNull(processor); + assertTrue(processor.isBulkheadEnabled()); + } + + private ResilienceProcessor findResilienceProcessor() { + return findResilienceProcessor("start"); + } + + private ResilienceProcessor findResilienceProcessor(String routeSuffix) { + Route route = context.getRoute(routeSuffix); + assertNotNull(route, "Route '" + routeSuffix + "' not found"); + return findResilienceProcessor(route.navigate()); + } + + private ResilienceProcessor findResilienceProcessor(Navigate navigate) { + for (Processor processor : navigate.next()) { + if (processor instanceof ResilienceProcessor) { + return (ResilienceProcessor) processor; + } + if (processor instanceof Navigate) { + @SuppressWarnings("unchecked") + Navigate nav = (Navigate) processor; + if (nav.hasNext()) { + ResilienceProcessor found = findResilienceProcessor(nav); + if (found != null) { + return found; + } + } + } + } + return null; + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start").routeId("start") + .circuitBreaker() + .resilience4jConfiguration() + .slidingWindowSynchronizationStrategy("LOCK_FREE") + .end() + .to("direct:foo") + .end() + .to("mock:result"); + + from("direct:start2").routeId("start2") + .circuitBreaker() + .resilience4jConfiguration() + .maxWaitDurationInHalfOpenState("30s") + .end() + .to("direct:foo") + .end() + .to("mock:result2"); + + from("direct:start3").routeId("start3") + .circuitBreaker() + .resilience4jConfiguration() + .bulkheadEnabled(true) + .bulkheadFairCallHandlingEnabled(false) + .end() + .to("direct:foo") + .end() + .to("mock:result3"); + + from("direct:foo").transform().constant("Bye World"); + } + }; + } +} diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResiliencePooledFallbackTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResiliencePooledFallbackTest.java new file mode 100644 index 0000000000000..930cf2ee56ddc --- /dev/null +++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResiliencePooledFallbackTest.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.resilience4j; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.impl.engine.PooledExchangeFactory; +import org.apache.camel.impl.engine.PooledProcessorExchangeFactory; +import org.apache.camel.spi.CircuitBreakerConstants; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.apache.camel.test.junit6.TestSupport.assertIsInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class ResiliencePooledFallbackTest extends CamelTestSupport { + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + context.getCamelContextExtension().setExchangeFactory(new PooledExchangeFactory()); + context.getCamelContextExtension().setProcessorExchangeFactory(new PooledProcessorExchangeFactory()); + return context; + } + + @Test + public void testFallbackExceptionCaughtPooled() throws Exception { + getMockEndpoint("mock:result").expectedBodiesReceived("Fallback message"); + getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false); + getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true); + getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SHORT_CIRCUITED, true); + + template.sendBody("direct:start", "Hello World"); + + MockEndpoint.assertIsSatisfied(context); + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .circuitBreaker() + .throwException(new IllegalArgumentException("Forced")) + .onFallback() + .process(e -> { + Throwable caught = e.getProperty(Exchange.EXCEPTION_CAUGHT, Throwable.class); + assertIsInstanceOf(IllegalArgumentException.class, caught); + assertNull(e.getException()); + }) + .transform().constant("Fallback message") + .end() + .to("mock:result"); + } + }; + } +} diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResiliencePooledTimeoutTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResiliencePooledTimeoutTest.java new file mode 100644 index 0000000000000..299a707eb13e3 --- /dev/null +++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResiliencePooledTimeoutTest.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.resilience4j; + +import java.util.concurrent.TimeoutException; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.impl.engine.PooledExchangeFactory; +import org.apache.camel.impl.engine.PooledProcessorExchangeFactory; +import org.apache.camel.spi.CircuitBreakerConstants; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.apache.camel.test.junit6.TestSupport.assertIsInstanceOf; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class ResiliencePooledTimeoutTest extends CamelTestSupport { + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + context.getCamelContextExtension().setExchangeFactory(new PooledExchangeFactory()); + context.getCamelContextExtension().setProcessorExchangeFactory(new PooledProcessorExchangeFactory()); + return context; + } + + @Test + public void testTimeoutExchangePropertiesPooled() { + Exchange out = template.send("direct:start", e -> e.getIn().setBody("Hello World")); + + assertNotNull(out.getException()); + assertIsInstanceOf(TimeoutException.class, out.getException()); + assertEquals(false, out.getProperty(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION)); + assertEquals(false, out.getProperty(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK)); + assertEquals(false, out.getProperty(CircuitBreakerConstants.RESPONSE_SHORT_CIRCUITED)); + assertEquals(true, out.getProperty(CircuitBreakerConstants.RESPONSE_TIMED_OUT)); + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .circuitBreaker() + .resilience4jConfiguration().timeoutEnabled(true).timeoutDuration(2000).end() + .to("direct:slow") + .end(); + + from("direct:slow") + .delay(5000).transform().constant("Slow response"); + } + }; + } +} diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceTimeoutExchangePropertyTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceTimeoutExchangePropertyTest.java new file mode 100644 index 0000000000000..e5e921d6d573e --- /dev/null +++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceTimeoutExchangePropertyTest.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.resilience4j; + +import java.util.concurrent.TimeoutException; + +import org.apache.camel.Exchange; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.spi.CircuitBreakerConstants; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.apache.camel.test.junit6.TestSupport.assertIsInstanceOf; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class ResilienceTimeoutExchangePropertyTest extends CamelTestSupport { + + @Test + public void testTimeoutExchangeProperties() { + Exchange out = template.send("direct:start", e -> e.getIn().setBody("Hello World")); + + assertNotNull(out.getException()); + assertIsInstanceOf(TimeoutException.class, out.getException()); + assertEquals(false, out.getProperty(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION)); + assertEquals(false, out.getProperty(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK)); + assertEquals(false, out.getProperty(CircuitBreakerConstants.RESPONSE_SHORT_CIRCUITED)); + assertEquals(true, out.getProperty(CircuitBreakerConstants.RESPONSE_TIMED_OUT)); + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .circuitBreaker() + .resilience4jConfiguration().timeoutEnabled(true).timeoutDuration(2000).end() + .to("direct:slow") + .end(); + + from("direct:slow") + .delay(5000).transform().constant("Slow response"); + } + }; + } +} diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceTimeoutWithFallbackExchangePropertyTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceTimeoutWithFallbackExchangePropertyTest.java new file mode 100644 index 0000000000000..167617ea991ad --- /dev/null +++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceTimeoutWithFallbackExchangePropertyTest.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.resilience4j; + +import java.util.concurrent.TimeoutException; + +import org.apache.camel.Exchange; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spi.CircuitBreakerConstants; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.apache.camel.test.junit6.TestSupport.assertIsInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class ResilienceTimeoutWithFallbackExchangePropertyTest extends CamelTestSupport { + + @Test + public void testTimeoutWithFallbackExchangeProperties() throws Exception { + getMockEndpoint("mock:result").expectedBodiesReceived("Fallback response"); + getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false); + getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true); + getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_TIMED_OUT, true); + + template.sendBody("direct:start", "Hello World"); + + MockEndpoint.assertIsSatisfied(context); + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:start") + .circuitBreaker() + .resilience4jConfiguration().timeoutEnabled(true).timeoutDuration(2000).end() + .to("direct:slow") + .onFallback() + .process(e -> { + Throwable caught = e.getProperty(Exchange.EXCEPTION_CAUGHT, Throwable.class); + assertIsInstanceOf(TimeoutException.class, caught); + assertNull(e.getException()); + }) + .transform().constant("Fallback response") + .end() + .to("mock:result"); + + from("direct:slow") + .delay(5000).transform().constant("Slow response"); + } + }; + } +} diff --git a/core/camel-core-model/src/generated/java/org/apache/camel/model/Resilience4jConfigurationDefinitionConfigurer.java b/core/camel-core-model/src/generated/java/org/apache/camel/model/Resilience4jConfigurationDefinitionConfigurer.java index e39a21bcf02b4..3504155b89f52 100644 --- a/core/camel-core-model/src/generated/java/org/apache/camel/model/Resilience4jConfigurationDefinitionConfigurer.java +++ b/core/camel-core-model/src/generated/java/org/apache/camel/model/Resilience4jConfigurationDefinitionConfigurer.java @@ -24,6 +24,7 @@ public class Resilience4jConfigurationDefinitionConfigurer extends org.apache.ca Map map = new CaseInsensitiveMap(); map.put("AutomaticTransitionFromOpenToHalfOpenEnabled", java.lang.String.class); map.put("BulkheadEnabled", java.lang.String.class); + map.put("BulkheadFairCallHandlingEnabled", java.lang.String.class); map.put("BulkheadMaxConcurrentCalls", java.lang.String.class); map.put("BulkheadMaxWaitDuration", java.lang.String.class); map.put("CircuitBreaker", java.lang.String.class); @@ -31,11 +32,13 @@ public class Resilience4jConfigurationDefinitionConfigurer extends org.apache.ca map.put("FailureRateThreshold", java.lang.String.class); map.put("Id", java.lang.String.class); map.put("IgnoreExceptions", java.util.List.class); + map.put("MaxWaitDurationInHalfOpenState", java.lang.String.class); map.put("MicrometerEnabled", java.lang.String.class); map.put("MinimumNumberOfCalls", java.lang.String.class); map.put("PermittedNumberOfCallsInHalfOpenState", java.lang.String.class); map.put("RecordExceptions", java.util.List.class); map.put("SlidingWindowSize", java.lang.String.class); + map.put("SlidingWindowSynchronizationStrategy", java.lang.String.class); map.put("SlidingWindowType", java.lang.String.class); map.put("SlowCallDurationThreshold", java.lang.String.class); map.put("SlowCallRateThreshold", java.lang.String.class); @@ -57,6 +60,8 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "automaticTransitionFromOpenToHalfOpenEnabled": target.setAutomaticTransitionFromOpenToHalfOpenEnabled(property(camelContext, java.lang.String.class, value)); return true; case "bulkheadenabled": case "bulkheadEnabled": target.setBulkheadEnabled(property(camelContext, java.lang.String.class, value)); return true; + case "bulkheadfaircallhandlingenabled": + case "bulkheadFairCallHandlingEnabled": target.setBulkheadFairCallHandlingEnabled(property(camelContext, java.lang.String.class, value)); return true; case "bulkheadmaxconcurrentcalls": case "bulkheadMaxConcurrentCalls": target.setBulkheadMaxConcurrentCalls(property(camelContext, java.lang.String.class, value)); return true; case "bulkheadmaxwaitduration": @@ -69,6 +74,8 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "id": target.setId(property(camelContext, java.lang.String.class, value)); return true; case "ignoreexceptions": case "ignoreExceptions": target.setIgnoreExceptions(property(camelContext, java.util.List.class, value)); return true; + case "maxwaitdurationinhalfopenstate": + case "maxWaitDurationInHalfOpenState": target.setMaxWaitDurationInHalfOpenState(property(camelContext, java.lang.String.class, value)); return true; case "micrometerenabled": case "micrometerEnabled": target.setMicrometerEnabled(property(camelContext, java.lang.String.class, value)); return true; case "minimumnumberofcalls": @@ -79,6 +86,8 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "recordExceptions": target.setRecordExceptions(property(camelContext, java.util.List.class, value)); return true; case "slidingwindowsize": case "slidingWindowSize": target.setSlidingWindowSize(property(camelContext, java.lang.String.class, value)); return true; + case "slidingwindowsynchronizationstrategy": + case "slidingWindowSynchronizationStrategy": target.setSlidingWindowSynchronizationStrategy(property(camelContext, java.lang.String.class, value)); return true; case "slidingwindowtype": case "slidingWindowType": target.setSlidingWindowType(property(camelContext, java.lang.String.class, value)); return true; case "slowcalldurationthreshold": @@ -115,6 +124,8 @@ public Class getOptionType(String name, boolean ignoreCase) { case "automaticTransitionFromOpenToHalfOpenEnabled": return java.lang.String.class; case "bulkheadenabled": case "bulkheadEnabled": return java.lang.String.class; + case "bulkheadfaircallhandlingenabled": + case "bulkheadFairCallHandlingEnabled": return java.lang.String.class; case "bulkheadmaxconcurrentcalls": case "bulkheadMaxConcurrentCalls": return java.lang.String.class; case "bulkheadmaxwaitduration": @@ -127,6 +138,8 @@ public Class getOptionType(String name, boolean ignoreCase) { case "id": return java.lang.String.class; case "ignoreexceptions": case "ignoreExceptions": return java.util.List.class; + case "maxwaitdurationinhalfopenstate": + case "maxWaitDurationInHalfOpenState": return java.lang.String.class; case "micrometerenabled": case "micrometerEnabled": return java.lang.String.class; case "minimumnumberofcalls": @@ -137,6 +150,8 @@ public Class getOptionType(String name, boolean ignoreCase) { case "recordExceptions": return java.util.List.class; case "slidingwindowsize": case "slidingWindowSize": return java.lang.String.class; + case "slidingwindowsynchronizationstrategy": + case "slidingWindowSynchronizationStrategy": return java.lang.String.class; case "slidingwindowtype": case "slidingWindowType": return java.lang.String.class; case "slowcalldurationthreshold": @@ -169,6 +184,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "automaticTransitionFromOpenToHalfOpenEnabled": return target.getAutomaticTransitionFromOpenToHalfOpenEnabled(); case "bulkheadenabled": case "bulkheadEnabled": return target.getBulkheadEnabled(); + case "bulkheadfaircallhandlingenabled": + case "bulkheadFairCallHandlingEnabled": return target.getBulkheadFairCallHandlingEnabled(); case "bulkheadmaxconcurrentcalls": case "bulkheadMaxConcurrentCalls": return target.getBulkheadMaxConcurrentCalls(); case "bulkheadmaxwaitduration": @@ -181,6 +198,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "id": return target.getId(); case "ignoreexceptions": case "ignoreExceptions": return target.getIgnoreExceptions(); + case "maxwaitdurationinhalfopenstate": + case "maxWaitDurationInHalfOpenState": return target.getMaxWaitDurationInHalfOpenState(); case "micrometerenabled": case "micrometerEnabled": return target.getMicrometerEnabled(); case "minimumnumberofcalls": @@ -191,6 +210,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "recordExceptions": return target.getRecordExceptions(); case "slidingwindowsize": case "slidingWindowSize": return target.getSlidingWindowSize(); + case "slidingwindowsynchronizationstrategy": + case "slidingWindowSynchronizationStrategy": return target.getSlidingWindowSynchronizationStrategy(); case "slidingwindowtype": case "slidingWindowType": return target.getSlidingWindowType(); case "slowcalldurationthreshold": diff --git a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/onFallback.json b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/onFallback.json index fcc732c0c3631..115d7228f5889 100644 --- a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/onFallback.json +++ b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/onFallback.json @@ -16,7 +16,7 @@ "id": { "index": 0, "kind": "attribute", "displayName": "Id", "group": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The id of this node" }, "note": { "index": 1, "kind": "attribute", "displayName": "Note", "group": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The note for this node" }, "description": { "index": 2, "kind": "attribute", "displayName": "Description", "group": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The description for this node" }, - "fallbackViaNetwork": { "index": 3, "kind": "attribute", "displayName": "Fallback Via Network", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the fallback goes over the network. If so, the fallback is executed on a separate thread-pool to avoid exhausting the main thread-pool." }, + "fallbackViaNetwork": { "index": 3, "kind": "attribute", "displayName": "Fallback Via Network", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": true, "deprecationNote": "Not supported by any circuit breaker implementation.", "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the fallback goes over the network. If so, the fallback is executed on a separate thread-pool to avoid exhausting the main thread-pool." }, "outputs": { "index": 4, "kind": "element", "displayName": "Outputs", "group": "common", "required": true, "type": "array", "javaType": "java.util.List>", "oneOf": [ "a2aSubTask", "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onException", "pausable", "pipeline", "policy", "poll", "pollEnrich", "process", "recipientList", "removeHeader", "removeHeaders", "removeProperties", "removeProperty", "removeVariable", "resequence", "resumable", "rollback", "routingSlip", "saga", "sample", "script", "setBody", "setExchangePattern", "setHeader", "setHeaders", "setProperty", "setVariable", "setVariables", "sort", "split", "step", "stop", "threads", "throttle", "throwException", "to", "toD", "tokenizer", "transacted", "transform", "transformDataType", "unmarshal", "validate", "wireTap" ], "deprecated": false, "autowired": false, "secret": false } } } 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 e2ee2d25745bb..9b1452808a393 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 @@ -20,21 +20,24 @@ "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 because the circuit breaker is half open or open." }, "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. Sliding window can either be count-based or time-based." }, "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 can either be count-based or time-based." }, - "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." }, - "writableStackTraceEnabled": { "index": 9, "kind": "attribute", "displayName": "Writable Stack Trace Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Enables writable stack traces. When set to false, Exception.getStackTrace returns a zero length array. This may be used to reduce log spam when the circuit breaker is open." }, - "waitDurationInOpenState": { "index": 10, "kind": "attribute", "displayName": "Wait Duration In Open State", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 60, "description": "Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it switches to half open." }, - "automaticTransitionFromOpenToHalfOpenEnabled": { "index": 11, "kind": "attribute", "displayName": "Automatic Transition From Open To Half Open Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enables automatic transition from OPEN to HALF_OPEN state once the waitDurationInOpenState has passed." }, - "slowCallRateThreshold": { "index": 12, "kind": "attribute", "displayName": "Slow Call Rate Threshold", "group": "advanced", "label": "advanced", "required": false, "type": "number", "javaType": "java.lang.Float", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "100", "description": "Configures a threshold in percentage. The CircuitBreaker considers a call as slow when the call duration is greater than slowCallDurationThreshold. When the percentage of slow calls is equal or greater the threshold, the CircuitBreaker transitions to open and starts short-circuiting calls." }, - "slowCallDurationThreshold": { "index": 13, "kind": "attribute", "displayName": "Slow Call Duration Threshold", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 60, "description": "Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls percentage." }, - "bulkheadEnabled": { "index": 14, "kind": "attribute", "displayName": "Bulkhead Enabled", "group": "common", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether bulkhead is enabled or not on the circuit breaker." }, - "bulkheadMaxConcurrentCalls": { "index": 15, "kind": "attribute", "displayName": "Bulkhead Max Concurrent Calls", "group": "common", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 25, "description": "Configures the max amount of concurrent calls the bulkhead will support." }, - "bulkheadMaxWaitDuration": { "index": 16, "kind": "attribute", "displayName": "Bulkhead Max Wait Duration", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 0, "description": "Configures a maximum amount of time which the calling thread will wait to enter the bulkhead." }, - "timeoutEnabled": { "index": 17, "kind": "attribute", "displayName": "Timeout Enabled", "group": "common", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether timeout is enabled or not on the circuit breaker." }, - "timeoutExecutorService": { "index": 18, "kind": "attribute", "displayName": "Timeout Executor Service", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.util.concurrent.ExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "References to a custom thread pool to use when timeout is enabled (uses ForkJoinPool.commonPool() by default)." }, - "timeoutDuration": { "index": 19, "kind": "attribute", "displayName": "Timeout Duration", "group": "common", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1000, "description": "Configures the thread execution timeout. Default value is 1 second." }, - "timeoutCancelRunningFuture": { "index": 20, "kind": "attribute", "displayName": "Timeout Cancel Running Future", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Configures whether cancel is called on the running future. Defaults to true." }, - "micrometerEnabled": { "index": 21, "kind": "attribute", "displayName": "Micrometer Enabled", "group": "common", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to enable collecting statistics using Micrometer. This requires adding camel-resilience4j-micrometer JAR to the classpath." }, - "recordException": { "index": 22, "kind": "element", "displayName": "Record Exception", "group": "advanced", "label": "advanced", "required": false, "type": "array", "javaType": "java.util.List", "deprecated": false, "autowired": false, "secret": false, "description": "Configure a list of exceptions that are recorded as a failure and thus increase the failure rate. Any exception matching or inheriting from one of the list counts as a failure, unless explicitly ignored via ignoreExceptions." }, - "ignoreException": { "index": 23, "kind": "element", "displayName": "Ignore Exception", "group": "advanced", "label": "advanced", "required": false, "type": "array", "javaType": "java.util.List", "deprecated": false, "autowired": false, "secret": false, "description": "Configure a list of exceptions that are ignored and neither count as a failure nor success. Any exception matching or inheriting from one of the list will not count as a failure nor success, even if the exception is part of recordExceptions." } + "slidingWindowSynchronizationStrategy": { "index": 8, "kind": "attribute", "displayName": "Sliding Window Synchronization Strategy", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "LOCK_FREE", "SYNCHRONIZED" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "SYNCHRONIZED", "description": "Configures the synchronization strategy for the sliding window. LOCK_FREE uses a CAS-based lock-free algorithm for better performance under high concurrency. SYNCHRONIZED uses blocking locks with lower memory allocation." }, + "minimumNumberOfCalls": { "index": 9, "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." }, + "writableStackTraceEnabled": { "index": 10, "kind": "attribute", "displayName": "Writable Stack Trace Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Enables writable stack traces. When set to false, Exception.getStackTrace returns a zero length array. This may be used to reduce log spam when the circuit breaker is open." }, + "waitDurationInOpenState": { "index": 11, "kind": "attribute", "displayName": "Wait Duration In Open State", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "60000", "description": "Configures the wait duration which specifies how long the CircuitBreaker should stay open, before it switches to half open. The default is 60 seconds." }, + "automaticTransitionFromOpenToHalfOpenEnabled": { "index": 12, "kind": "attribute", "displayName": "Automatic Transition From Open To Half Open Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enables automatic transition from OPEN to HALF_OPEN state once the waitDurationInOpenState has passed." }, + "maxWaitDurationInHalfOpenState": { "index": 13, "kind": "attribute", "displayName": "Max Wait Duration In Half Open State", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "0", "description": "Configures the maximum wait duration which controls how long the CircuitBreaker should stay in Half Open state, before it switches to open. Value 0 means circuit breaker will wait in half open state until all permitted calls have been completed." }, + "slowCallRateThreshold": { "index": 14, "kind": "attribute", "displayName": "Slow Call Rate Threshold", "group": "advanced", "label": "advanced", "required": false, "type": "number", "javaType": "java.lang.Float", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "100", "description": "Configures a threshold in percentage. The CircuitBreaker considers a call as slow when the call duration is greater than slowCallDurationThreshold. When the percentage of slow calls is equal or greater the threshold, the CircuitBreaker transitions to open and starts short-circuiting calls." }, + "slowCallDurationThreshold": { "index": 15, "kind": "attribute", "displayName": "Slow Call Duration Threshold", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "60000", "description": "Configures the duration threshold above which calls are considered as slow and increase the slow calls percentage. The default is 60 seconds." }, + "bulkheadEnabled": { "index": 16, "kind": "attribute", "displayName": "Bulkhead Enabled", "group": "common", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether bulkhead is enabled or not on the circuit breaker." }, + "bulkheadMaxConcurrentCalls": { "index": 17, "kind": "attribute", "displayName": "Bulkhead Max Concurrent Calls", "group": "common", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 25, "description": "Configures the max amount of concurrent calls the bulkhead will support." }, + "bulkheadMaxWaitDuration": { "index": 18, "kind": "attribute", "displayName": "Bulkhead Max Wait Duration", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "0", "description": "Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. The default is 0 (no waiting)." }, + "bulkheadFairCallHandlingEnabled": { "index": 19, "kind": "attribute", "displayName": "Bulkhead Fair Call Handling Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Configures whether the bulkhead uses a fair calling strategy. When enabled (default), a fair strategy guarantees the order of incoming requests (FIFO). When disabled, no ordering is guaranteed and may improve throughput." }, + "timeoutEnabled": { "index": 20, "kind": "attribute", "displayName": "Timeout Enabled", "group": "common", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether timeout is enabled or not on the circuit breaker." }, + "timeoutExecutorService": { "index": 21, "kind": "attribute", "displayName": "Timeout Executor Service", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.util.concurrent.ExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "References to a custom thread pool to use when timeout is enabled (uses ForkJoinPool.commonPool() by default)." }, + "timeoutDuration": { "index": 22, "kind": "attribute", "displayName": "Timeout Duration", "group": "common", "required": false, "type": "duration", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "1000", "description": "Configures the thread execution timeout. Default value is 1 second." }, + "timeoutCancelRunningFuture": { "index": 23, "kind": "attribute", "displayName": "Timeout Cancel Running Future", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Configures whether cancel is called on the running future. Defaults to true." }, + "micrometerEnabled": { "index": 24, "kind": "attribute", "displayName": "Micrometer Enabled", "group": "common", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to enable collecting statistics using Micrometer for all circuit breaker instances. This is a global setting (configure via camel.resilience4j.micrometerEnabled=true) and requires adding camel-resilience4j-micrometer JAR to the classpath." }, + "recordException": { "index": 25, "kind": "element", "displayName": "Record Exception", "group": "advanced", "label": "advanced", "required": false, "type": "array", "javaType": "java.util.List", "deprecated": false, "autowired": false, "secret": false, "description": "Configure a list of exceptions that are recorded as a failure and thus increase the failure rate. Any exception matching or inheriting from one of the list counts as a failure, unless explicitly ignored via ignoreExceptions." }, + "ignoreException": { "index": 26, "kind": "element", "displayName": "Ignore Exception", "group": "advanced", "label": "advanced", "required": false, "type": "array", "javaType": "java.util.List", "deprecated": false, "autowired": false, "secret": false, "description": "Configure a list of exceptions that are ignored and neither count as a failure nor success. Any exception matching or inheriting from one of the list will not count as a failure nor success, even if the exception is part of recordExceptions." } } } diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/CircuitBreakerDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/CircuitBreakerDefinition.java index 5dd24e68c7e46..32a64820b3171 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/CircuitBreakerDefinition.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/CircuitBreakerDefinition.java @@ -218,10 +218,7 @@ public CircuitBreakerDefinition inheritErrorHandler(boolean inheritErrorHandler) } /** - * The fallback route path to execute that does not go over the network. - *

- * This should be a static or cached result that can immediately be returned upon failure. If the fallback requires - * network connection then use {@link #onFallbackViaNetwork()}. + * The fallback route path to execute when the circuit breaker triggers. */ public CircuitBreakerDefinition onFallback() { onFallback = new OnFallbackDefinition(); @@ -233,7 +230,10 @@ public CircuitBreakerDefinition onFallback() { * The fallback route path to execute that will go over the network. *

* If the fallback will go over the network it is another possible point of failure. + * + * @deprecated Not supported by any circuit breaker implementation. Use {@link #onFallback()} instead. */ + @Deprecated(since = "4.22", forRemoval = true) public CircuitBreakerDefinition onFallbackViaNetwork() { onFallback = new OnFallbackDefinition(); onFallback.setFallbackViaNetwork(Boolean.toString(true)); diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/OnFallbackDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/OnFallbackDefinition.java index 3e737b87bfa6c..319be4f80e7ee 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/OnFallbackDefinition.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/OnFallbackDefinition.java @@ -46,7 +46,9 @@ public class OnFallbackDefinition extends OptionalIdentifiedDefinition parent; @XmlAttribute @Metadata(label = "advanced", defaultValue = "false", javaType = "java.lang.Boolean", + deprecationNote = "Not supported by any circuit breaker implementation.", description = "Whether the fallback goes over the network. If so, the fallback is executed on a separate thread-pool to avoid exhausting the main thread-pool.") + @Deprecated(since = "4.22", forRemoval = true) private String fallbackViaNetwork; @XmlElementRef @Metadata(description = "The processing steps to execute as fallback.") @@ -105,10 +107,12 @@ public String getLabel() { .collect(Collectors.joining(",", name + "[", "]")); } + @Deprecated(since = "4.22", forRemoval = true) public String getFallbackViaNetwork() { return fallbackViaNetwork; } + @Deprecated(since = "4.22", forRemoval = true) public void setFallbackViaNetwork(String fallbackViaNetwork) { this.fallbackViaNetwork = fallbackViaNetwork; } 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 f465d2c9edad1..0724a98c8f7be 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 @@ -63,6 +63,12 @@ public class Resilience4jConfigurationCommon extends IdentifiedType { + " Sliding window can either be count-based or time-based.") private String slidingWindowType; @XmlAttribute + @Metadata(label = "advanced", defaultValue = "SYNCHRONIZED", enums = "LOCK_FREE,SYNCHRONIZED", + description = "Configures the synchronization strategy for the sliding window." + + " LOCK_FREE uses a CAS-based lock-free algorithm for better performance under high concurrency." + + " SYNCHRONIZED uses blocking locks with lower memory allocation.") + private String slidingWindowSynchronizationStrategy; + @XmlAttribute @Metadata(defaultValue = "100", javaType = "java.lang.Integer", description = "Configures the minimum number of calls which are required (per sliding window period) before the CircuitBreaker can calculate the error rate.") private String minimumNumberOfCalls; @@ -72,21 +78,29 @@ public class Resilience4jConfigurationCommon extends IdentifiedType { + " This may be used to reduce log spam when the circuit breaker is open.") private String writableStackTraceEnabled; @XmlAttribute - @Metadata(label = "advanced", defaultValue = "60", javaType = "java.lang.Integer", - description = "Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it switches to half open.") + @Metadata(label = "advanced", defaultValue = "60000", javaType = "java.time.Duration", + description = "Configures the wait duration which specifies how long the CircuitBreaker should stay open, before it switches to half open." + + " The default is 60 seconds.") private String waitDurationInOpenState; @XmlAttribute @Metadata(label = "advanced", defaultValue = "false", javaType = "java.lang.Boolean", description = "Enables automatic transition from OPEN to HALF_OPEN state once the waitDurationInOpenState has passed.") private String automaticTransitionFromOpenToHalfOpenEnabled; @XmlAttribute + @Metadata(label = "advanced", defaultValue = "0", javaType = "java.time.Duration", + description = "Configures the maximum wait duration which controls how long the CircuitBreaker should stay in Half Open state," + + " before it switches to open. Value 0 means circuit breaker will wait in half open state" + + " until all permitted calls have been completed.") + private String maxWaitDurationInHalfOpenState; + @XmlAttribute @Metadata(label = "advanced", defaultValue = "100", javaType = "java.lang.Float", description = "Configures a threshold in percentage. The CircuitBreaker considers a call as slow when the call duration is greater than slowCallDurationThreshold." + " When the percentage of slow calls is equal or greater the threshold, the CircuitBreaker transitions to open and starts short-circuiting calls.") private String slowCallRateThreshold; @XmlAttribute - @Metadata(label = "advanced", defaultValue = "60", javaType = "java.lang.Integer", - description = "Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls percentage.") + @Metadata(label = "advanced", defaultValue = "60000", javaType = "java.time.Duration", + description = "Configures the duration threshold above which calls are considered as slow and increase the slow calls percentage." + + " The default is 60 seconds.") private String slowCallDurationThreshold; @XmlAttribute @Metadata(defaultValue = "false", javaType = "java.lang.Boolean", @@ -97,10 +111,17 @@ public class Resilience4jConfigurationCommon extends IdentifiedType { description = "Configures the max amount of concurrent calls the bulkhead will support.") private String bulkheadMaxConcurrentCalls; @XmlAttribute - @Metadata(label = "advanced", defaultValue = "0", javaType = "java.lang.Integer", - description = "Configures a maximum amount of time which the calling thread will wait to enter the bulkhead.") + @Metadata(label = "advanced", defaultValue = "0", javaType = "java.time.Duration", + description = "Configures a maximum amount of time which the calling thread will wait to enter the bulkhead." + + " The default is 0 (no waiting).") private String bulkheadMaxWaitDuration; @XmlAttribute + @Metadata(label = "advanced", defaultValue = "true", javaType = "java.lang.Boolean", + description = "Configures whether the bulkhead uses a fair calling strategy." + + " When enabled (default), a fair strategy guarantees the order of incoming requests (FIFO)." + + " When disabled, no ordering is guaranteed and may improve throughput.") + private String bulkheadFairCallHandlingEnabled; + @XmlAttribute @Metadata(defaultValue = "false", javaType = "java.lang.Boolean", description = "Whether timeout is enabled or not on the circuit breaker.") private String timeoutEnabled; @@ -109,7 +130,7 @@ public class Resilience4jConfigurationCommon extends IdentifiedType { description = "References to a custom thread pool to use when timeout is enabled (uses ForkJoinPool.commonPool() by default).") private String timeoutExecutorService; @XmlAttribute - @Metadata(defaultValue = "1000", javaType = "java.lang.Integer", + @Metadata(defaultValue = "1000", javaType = "java.time.Duration", description = "Configures the thread execution timeout. Default value is 1 second.") private String timeoutDuration; @XmlAttribute @@ -118,7 +139,9 @@ public class Resilience4jConfigurationCommon extends IdentifiedType { private String timeoutCancelRunningFuture; @XmlAttribute @Metadata(defaultValue = "false", javaType = "java.lang.Boolean", - description = "Whether to enable collecting statistics using Micrometer. This requires adding camel-resilience4j-micrometer JAR to the classpath.") + description = "Whether to enable collecting statistics using Micrometer for all circuit breaker instances." + + " This is a global setting (configure via camel.resilience4j.micrometerEnabled=true)" + + " and requires adding camel-resilience4j-micrometer JAR to the classpath.") private String micrometerEnabled; @XmlElement(name = "recordException") @Metadata(label = "advanced", @@ -142,15 +165,18 @@ protected Resilience4jConfigurationCommon(Resilience4jConfigurationCommon source this.throwExceptionWhenHalfOpenOrOpenState = source.throwExceptionWhenHalfOpenOrOpenState; this.slidingWindowSize = source.slidingWindowSize; this.slidingWindowType = source.slidingWindowType; + this.slidingWindowSynchronizationStrategy = source.slidingWindowSynchronizationStrategy; this.minimumNumberOfCalls = source.minimumNumberOfCalls; this.writableStackTraceEnabled = source.writableStackTraceEnabled; this.waitDurationInOpenState = source.waitDurationInOpenState; this.automaticTransitionFromOpenToHalfOpenEnabled = source.automaticTransitionFromOpenToHalfOpenEnabled; + this.maxWaitDurationInHalfOpenState = source.maxWaitDurationInHalfOpenState; this.slowCallRateThreshold = source.slowCallRateThreshold; this.slowCallDurationThreshold = source.slowCallDurationThreshold; this.bulkheadEnabled = source.bulkheadEnabled; this.bulkheadMaxConcurrentCalls = source.bulkheadMaxConcurrentCalls; this.bulkheadMaxWaitDuration = source.bulkheadMaxWaitDuration; + this.bulkheadFairCallHandlingEnabled = source.bulkheadFairCallHandlingEnabled; this.timeoutEnabled = source.timeoutEnabled; this.micrometerEnabled = source.micrometerEnabled; this.timeoutExecutorService = source.timeoutExecutorService; @@ -223,6 +249,14 @@ public void setSlidingWindowType(String slidingWindowType) { this.slidingWindowType = slidingWindowType; } + public String getSlidingWindowSynchronizationStrategy() { + return slidingWindowSynchronizationStrategy; + } + + public void setSlidingWindowSynchronizationStrategy(String slidingWindowSynchronizationStrategy) { + this.slidingWindowSynchronizationStrategy = slidingWindowSynchronizationStrategy; + } + public String getMinimumNumberOfCalls() { return minimumNumberOfCalls; } @@ -255,6 +289,14 @@ public void setAutomaticTransitionFromOpenToHalfOpenEnabled(String automaticTran this.automaticTransitionFromOpenToHalfOpenEnabled = automaticTransitionFromOpenToHalfOpenEnabled; } + public String getMaxWaitDurationInHalfOpenState() { + return maxWaitDurationInHalfOpenState; + } + + public void setMaxWaitDurationInHalfOpenState(String maxWaitDurationInHalfOpenState) { + this.maxWaitDurationInHalfOpenState = maxWaitDurationInHalfOpenState; + } + public String getSlowCallRateThreshold() { return slowCallRateThreshold; } @@ -295,6 +337,14 @@ public void setBulkheadMaxWaitDuration(String bulkheadMaxWaitDuration) { this.bulkheadMaxWaitDuration = bulkheadMaxWaitDuration; } + public String getBulkheadFairCallHandlingEnabled() { + return bulkheadFairCallHandlingEnabled; + } + + public void setBulkheadFairCallHandlingEnabled(String bulkheadFairCallHandlingEnabled) { + this.bulkheadFairCallHandlingEnabled = bulkheadFairCallHandlingEnabled; + } + public String getTimeoutEnabled() { return timeoutEnabled; } 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 7295c6f74d9fc..00e8540d2500a 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 @@ -180,6 +180,18 @@ public Resilience4jConfigurationDefinition slidingWindowType(String slidingWindo return this; } + /** + * Configures the synchronization strategy for the sliding window. LOCK_FREE uses a CAS-based lock-free algorithm + * for better performance under high concurrency. SYNCHRONIZED uses blocking locks with lower memory allocation. + * + * Default is SYNCHRONIZED. + */ + public Resilience4jConfigurationDefinition slidingWindowSynchronizationStrategy( + String slidingWindowSynchronizationStrategy) { + setSlidingWindowSynchronizationStrategy(slidingWindowSynchronizationStrategy); + return this; + } + /** * Configures configures the minimum number of calls which are required (per sliding window period) before the * CircuitBreaker can calculate the error rate. For example, if {@code minimumNumberOfCalls} is 10, then at least 10 @@ -221,16 +233,20 @@ public Resilience4jConfigurationDefinition writableStackTraceEnabled(String writ } /** - * Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it - * switches to half open. Default value is 60 seconds. + * Configures the wait duration (in millis) which specifies how long the CircuitBreaker should stay open, before it + * switches to half open. Default value is 60 seconds (60000 millis). + * + * @deprecated Use {@link #waitDurationInOpenState(String)} with a Camel duration expression (e.g. "60s", "1m"). */ + @Deprecated(since = "4.22", forRemoval = true) public Resilience4jConfigurationDefinition waitDurationInOpenState(int waitDurationInOpenState) { setWaitDurationInOpenState(Integer.toString(waitDurationInOpenState)); return this; } /** - * Configures the wait duration in open state (seconds). Supports property placeholders. + * Configures the wait duration in open state. Accepts a Camel duration (e.g. 60s, 1m, 60000) or ISO-8601 format + * (e.g. PT1M). Default value is 60 seconds. Supports property placeholders. */ public Resilience4jConfigurationDefinition waitDurationInOpenState(String waitDurationInOpenState) { setWaitDurationInOpenState(waitDurationInOpenState); @@ -255,6 +271,25 @@ public Resilience4jConfigurationDefinition automaticTransitionFromOpenToHalfOpen return this; } + /** + * Configures the maximum wait duration (in millis) which controls how long the CircuitBreaker should stay in Half + * Open state, before it switches to open. Value 0 means circuit breaker will wait in half open state until all + * permitted calls have been completed. + */ + public Resilience4jConfigurationDefinition maxWaitDurationInHalfOpenState(int maxWaitDurationInHalfOpenState) { + setMaxWaitDurationInHalfOpenState(Integer.toString(maxWaitDurationInHalfOpenState)); + return this; + } + + /** + * Configures the maximum wait duration which controls how long the CircuitBreaker should stay in Half Open state. + * Accepts a Camel duration (e.g. 30s, 1m, 30000) or ISO-8601 format (e.g. PT30S). Supports property placeholders. + */ + public Resilience4jConfigurationDefinition maxWaitDurationInHalfOpenState(String maxWaitDurationInHalfOpenState) { + setMaxWaitDurationInHalfOpenState(maxWaitDurationInHalfOpenState); + return this; + } + /** * 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 @@ -277,17 +312,20 @@ public Resilience4jConfigurationDefinition slowCallRateThreshold(String slowCall } /** - * Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls - * percentage. Default value is 60 seconds. + * Configures the duration threshold (in millis) above which calls are considered as slow and increase the slow + * calls percentage. Default value is 60 seconds (60000 millis). + * + * @deprecated Use {@link #slowCallDurationThreshold(String)} with a Camel duration expression (e.g. "60s", "1m"). */ + @Deprecated(since = "4.22", forRemoval = true) public Resilience4jConfigurationDefinition slowCallDurationThreshold(int slowCallDurationThreshold) { setSlowCallDurationThreshold(Integer.toString(slowCallDurationThreshold)); return this; } /** - * Configures the duration threshold (seconds) above which calls are considered as slow. Supports property - * placeholders. + * Configures the duration threshold above which calls are considered as slow. Accepts a Camel duration (e.g. 60s, + * 1m, 60000) or ISO-8601 format (e.g. PT1M). Default value is 60 seconds. Supports property placeholders. */ public Resilience4jConfigurationDefinition slowCallDurationThreshold(String slowCallDurationThreshold) { setSlowCallDurationThreshold(slowCallDurationThreshold); @@ -327,28 +365,48 @@ public Resilience4jConfigurationDefinition bulkheadMaxConcurrentCalls(String bul } /** - * Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. If bulkhead has - * space available, entry is guaranteed and immediate. If bulkhead is full, calling threads will contest for space, - * if it becomes available. maxWaitDuration can be set to 0. + * Configures a maximum amount of time (in millis) which the calling thread will wait to enter the bulkhead. If + * bulkhead has space available, entry is guaranteed and immediate. If bulkhead is full, calling threads will + * contest for space, if it becomes available. maxWaitDuration can be set to 0. *

* Note: for threads running on an event-loop or equivalent (rx computation pool, etc), setting maxWaitDuration to 0 * is highly recommended. Blocking an event-loop thread will most likely have a negative effect on application * throughput. + * + * @deprecated Use {@link #bulkheadMaxWaitDuration(String)} with a Camel duration expression (e.g. "500ms", "5s"). */ + @Deprecated(since = "4.22", forRemoval = true) public Resilience4jConfigurationDefinition bulkheadMaxWaitDuration(int bulkheadMaxWaitDuration) { setBulkheadMaxWaitDuration(Integer.toString(bulkheadMaxWaitDuration)); return this; } /** - * Configures a maximum amount of time for the calling thread to wait to enter the bulkhead. Supports property - * placeholders. + * Configures a maximum amount of time for the calling thread to wait to enter the bulkhead. Accepts a Camel + * duration (e.g. 500ms, 5s, 5000) or ISO-8601 format (e.g. PT5S). Supports property placeholders. */ public Resilience4jConfigurationDefinition bulkheadMaxWaitDuration(String bulkheadMaxWaitDuration) { setBulkheadMaxWaitDuration(bulkheadMaxWaitDuration); return this; } + /** + * Configures whether the bulkhead uses a fair calling strategy. When enabled (default), a fair strategy guarantees + * the order of incoming requests (FIFO). When disabled, no ordering is guaranteed and may improve throughput. + */ + public Resilience4jConfigurationDefinition bulkheadFairCallHandlingEnabled(boolean bulkheadFairCallHandlingEnabled) { + setBulkheadFairCallHandlingEnabled(Boolean.toString(bulkheadFairCallHandlingEnabled)); + return this; + } + + /** + * Configures whether the bulkhead uses a fair calling strategy. Supports property placeholders. + */ + public Resilience4jConfigurationDefinition bulkheadFairCallHandlingEnabled(String bulkheadFairCallHandlingEnabled) { + setBulkheadFairCallHandlingEnabled(bulkheadFairCallHandlingEnabled); + return this; + } + /** * Whether timeout is enabled or not on the circuit breaker. Default is false. */ @@ -375,15 +433,19 @@ public Resilience4jConfigurationDefinition timeoutExecutorService(String executo } /** - * Configures the thread execution timeout (millis). Default value is 1000 millis (1 second). + * Configures the thread execution timeout (in millis). Default value is 1000 millis (1 second). + * + * @deprecated Use {@link #timeoutDuration(String)} with a Camel duration expression (e.g. "1s", "500ms"). */ + @Deprecated(since = "4.22", forRemoval = true) public Resilience4jConfigurationDefinition timeoutDuration(int timeoutDuration) { setTimeoutDuration(Integer.toString(timeoutDuration)); return this; } /** - * Configures the thread execution timeout (millis). Supports property placeholders. + * Configures the thread execution timeout. Accepts a Camel duration (e.g. 1s, 1000, 500ms) or ISO-8601 format (e.g. + * PT1S). Default value is 1 second. Supports property placeholders. */ public Resilience4jConfigurationDefinition timeoutDuration(String timeoutDuration) { setTimeoutDuration(timeoutDuration); @@ -391,8 +453,9 @@ public Resilience4jConfigurationDefinition timeoutDuration(String timeoutDuratio } /** - * Whether to enable collecting statistics using Micrometer. This requires adding camel-resilience4j-micrometer JAR - * to the classpath. + * Whether to enable collecting statistics using Micrometer for all circuit breaker instances. This is a global + * setting (configure via camel.resilience4j.micrometerEnabled=true) and requires adding + * camel-resilience4j-micrometer JAR to the classpath. */ public Resilience4jConfigurationDefinition micrometerEnabled(boolean micrometerEnabled) { setMicrometerEnabled(Boolean.toString(micrometerEnabled)); @@ -400,7 +463,8 @@ public Resilience4jConfigurationDefinition micrometerEnabled(boolean micrometerE } /** - * Whether to enable collecting statistics using Micrometer. Supports property placeholders. + * Whether to enable collecting statistics using Micrometer for all circuit breaker instances. Supports property + * placeholders. */ public Resilience4jConfigurationDefinition micrometerEnabled(String micrometerEnabled) { setMicrometerEnabled(micrometerEnabled); diff --git a/core/camel-java-io/src/generated/java/org/apache/camel/java/out/JavaDslModelWriter.java b/core/camel-java-io/src/generated/java/org/apache/camel/java/out/JavaDslModelWriter.java index 81be1897de539..d9a3e8a1233da 100644 --- a/core/camel-java-io/src/generated/java/org/apache/camel/java/out/JavaDslModelWriter.java +++ b/core/camel-java-io/src/generated/java/org/apache/camel/java/out/JavaDslModelWriter.java @@ -2318,15 +2318,18 @@ protected void doWriteResilience4jConfigurationCommonAttributes(StringBuilder sb doWriteAttribute(sb, "throwExceptionWhenHalfOpenOrOpenState", def.getThrowExceptionWhenHalfOpenOrOpenState(), "false"); doWriteAttribute(sb, "slidingWindowSize", def.getSlidingWindowSize(), "100"); doWriteAttribute(sb, "slidingWindowType", def.getSlidingWindowType(), "COUNT_BASED"); + doWriteAttribute(sb, "slidingWindowSynchronizationStrategy", def.getSlidingWindowSynchronizationStrategy(), "SYNCHRONIZED"); doWriteAttribute(sb, "minimumNumberOfCalls", def.getMinimumNumberOfCalls(), "100"); doWriteAttribute(sb, "writableStackTraceEnabled", def.getWritableStackTraceEnabled(), "true"); - doWriteAttribute(sb, "waitDurationInOpenState", def.getWaitDurationInOpenState(), "60"); + doWriteAttribute(sb, "waitDurationInOpenState", def.getWaitDurationInOpenState(), "60000"); doWriteAttribute(sb, "automaticTransitionFromOpenToHalfOpenEnabled", def.getAutomaticTransitionFromOpenToHalfOpenEnabled(), "false"); + doWriteAttribute(sb, "maxWaitDurationInHalfOpenState", def.getMaxWaitDurationInHalfOpenState(), "0"); doWriteAttribute(sb, "slowCallRateThreshold", def.getSlowCallRateThreshold(), "100"); - doWriteAttribute(sb, "slowCallDurationThreshold", def.getSlowCallDurationThreshold(), "60"); + doWriteAttribute(sb, "slowCallDurationThreshold", def.getSlowCallDurationThreshold(), "60000"); doWriteAttribute(sb, "bulkheadEnabled", def.getBulkheadEnabled(), "false"); doWriteAttribute(sb, "bulkheadMaxConcurrentCalls", def.getBulkheadMaxConcurrentCalls(), "25"); doWriteAttribute(sb, "bulkheadMaxWaitDuration", def.getBulkheadMaxWaitDuration(), "0"); + doWriteAttribute(sb, "bulkheadFairCallHandlingEnabled", def.getBulkheadFairCallHandlingEnabled(), "true"); doWriteAttribute(sb, "timeoutEnabled", def.getTimeoutEnabled(), "false"); doWriteAttribute(sb, "timeoutExecutorService", def.getTimeoutExecutorService(), null); doWriteAttribute(sb, "timeoutDuration", def.getTimeoutDuration(), "1000"); diff --git a/core/camel-main/src/generated/java/org/apache/camel/main/Resilience4jConfigurationPropertiesConfigurer.java b/core/camel-main/src/generated/java/org/apache/camel/main/Resilience4jConfigurationPropertiesConfigurer.java index 4f6862c7766f9..3061525bb70ee 100644 --- a/core/camel-main/src/generated/java/org/apache/camel/main/Resilience4jConfigurationPropertiesConfigurer.java +++ b/core/camel-main/src/generated/java/org/apache/camel/main/Resilience4jConfigurationPropertiesConfigurer.java @@ -24,24 +24,27 @@ public class Resilience4jConfigurationPropertiesConfigurer extends org.apache.ca Map map = new CaseInsensitiveMap(); map.put("AutomaticTransitionFromOpenToHalfOpenEnabled", java.lang.Boolean.class); map.put("BulkheadEnabled", java.lang.Boolean.class); + map.put("BulkheadFairCallHandlingEnabled", java.lang.Boolean.class); map.put("BulkheadMaxConcurrentCalls", java.lang.Integer.class); - map.put("BulkheadMaxWaitDuration", java.lang.Integer.class); + map.put("BulkheadMaxWaitDuration", java.lang.String.class); map.put("CircuitBreaker", java.lang.String.class); map.put("Config", java.lang.String.class); map.put("FailureRateThreshold", java.lang.Float.class); + map.put("MaxWaitDurationInHalfOpenState", java.lang.String.class); map.put("MicrometerEnabled", java.lang.Boolean.class); map.put("MinimumNumberOfCalls", java.lang.Integer.class); map.put("PermittedNumberOfCallsInHalfOpenState", java.lang.Integer.class); map.put("SlidingWindowSize", java.lang.Integer.class); + map.put("SlidingWindowSynchronizationStrategy", java.lang.String.class); map.put("SlidingWindowType", java.lang.String.class); - map.put("SlowCallDurationThreshold", java.lang.Integer.class); + map.put("SlowCallDurationThreshold", java.lang.String.class); map.put("SlowCallRateThreshold", java.lang.Float.class); map.put("ThrowExceptionWhenHalfOpenOrOpenState", java.lang.Boolean.class); map.put("TimeoutCancelRunningFuture", java.lang.Boolean.class); - map.put("TimeoutDuration", java.lang.Integer.class); + map.put("TimeoutDuration", java.lang.String.class); map.put("TimeoutEnabled", java.lang.Boolean.class); map.put("TimeoutExecutorService", java.lang.String.class); - map.put("WaitDurationInOpenState", java.lang.Integer.class); + map.put("WaitDurationInOpenState", java.lang.String.class); map.put("WritableStackTraceEnabled", java.lang.Boolean.class); ALL_OPTIONS = map; } @@ -54,15 +57,19 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "automaticTransitionFromOpenToHalfOpenEnabled": target.setAutomaticTransitionFromOpenToHalfOpenEnabled(property(camelContext, java.lang.Boolean.class, value)); return true; case "bulkheadenabled": case "bulkheadEnabled": target.setBulkheadEnabled(property(camelContext, java.lang.Boolean.class, value)); return true; + case "bulkheadfaircallhandlingenabled": + case "bulkheadFairCallHandlingEnabled": target.setBulkheadFairCallHandlingEnabled(property(camelContext, java.lang.Boolean.class, value)); return true; case "bulkheadmaxconcurrentcalls": case "bulkheadMaxConcurrentCalls": target.setBulkheadMaxConcurrentCalls(property(camelContext, java.lang.Integer.class, value)); return true; case "bulkheadmaxwaitduration": - case "bulkheadMaxWaitDuration": target.setBulkheadMaxWaitDuration(property(camelContext, java.lang.Integer.class, value)); return true; + case "bulkheadMaxWaitDuration": target.setBulkheadMaxWaitDuration(property(camelContext, java.lang.String.class, value)); return true; case "circuitbreaker": case "circuitBreaker": target.setCircuitBreaker(property(camelContext, java.lang.String.class, value)); return true; case "config": target.setConfig(property(camelContext, java.lang.String.class, value)); return true; case "failureratethreshold": case "failureRateThreshold": target.setFailureRateThreshold(property(camelContext, java.lang.Float.class, value)); return true; + case "maxwaitdurationinhalfopenstate": + case "maxWaitDurationInHalfOpenState": target.setMaxWaitDurationInHalfOpenState(property(camelContext, java.lang.String.class, value)); return true; case "micrometerenabled": case "micrometerEnabled": target.setMicrometerEnabled(property(camelContext, java.lang.Boolean.class, value)); return true; case "minimumnumberofcalls": @@ -71,10 +78,12 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "permittedNumberOfCallsInHalfOpenState": target.setPermittedNumberOfCallsInHalfOpenState(property(camelContext, java.lang.Integer.class, value)); return true; case "slidingwindowsize": case "slidingWindowSize": target.setSlidingWindowSize(property(camelContext, java.lang.Integer.class, value)); return true; + case "slidingwindowsynchronizationstrategy": + case "slidingWindowSynchronizationStrategy": target.setSlidingWindowSynchronizationStrategy(property(camelContext, java.lang.String.class, value)); return true; case "slidingwindowtype": case "slidingWindowType": target.setSlidingWindowType(property(camelContext, java.lang.String.class, value)); return true; case "slowcalldurationthreshold": - case "slowCallDurationThreshold": target.setSlowCallDurationThreshold(property(camelContext, java.lang.Integer.class, value)); return true; + case "slowCallDurationThreshold": target.setSlowCallDurationThreshold(property(camelContext, java.lang.String.class, value)); return true; case "slowcallratethreshold": case "slowCallRateThreshold": target.setSlowCallRateThreshold(property(camelContext, java.lang.Float.class, value)); return true; case "throwexceptionwhenhalfopenoropenstate": @@ -82,13 +91,13 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "timeoutcancelrunningfuture": case "timeoutCancelRunningFuture": target.setTimeoutCancelRunningFuture(property(camelContext, java.lang.Boolean.class, value)); return true; case "timeoutduration": - case "timeoutDuration": target.setTimeoutDuration(property(camelContext, java.lang.Integer.class, value)); return true; + case "timeoutDuration": target.setTimeoutDuration(property(camelContext, java.lang.String.class, value)); return true; case "timeoutenabled": case "timeoutEnabled": target.setTimeoutEnabled(property(camelContext, java.lang.Boolean.class, value)); return true; case "timeoutexecutorservice": case "timeoutExecutorService": target.setTimeoutExecutorService(property(camelContext, java.lang.String.class, value)); return true; case "waitdurationinopenstate": - case "waitDurationInOpenState": target.setWaitDurationInOpenState(property(camelContext, java.lang.Integer.class, value)); return true; + case "waitDurationInOpenState": target.setWaitDurationInOpenState(property(camelContext, java.lang.String.class, value)); return true; case "writablestacktraceenabled": case "writableStackTraceEnabled": target.setWritableStackTraceEnabled(property(camelContext, java.lang.Boolean.class, value)); return true; default: return false; @@ -107,15 +116,19 @@ public Class getOptionType(String name, boolean ignoreCase) { case "automaticTransitionFromOpenToHalfOpenEnabled": return java.lang.Boolean.class; case "bulkheadenabled": case "bulkheadEnabled": return java.lang.Boolean.class; + case "bulkheadfaircallhandlingenabled": + case "bulkheadFairCallHandlingEnabled": return java.lang.Boolean.class; case "bulkheadmaxconcurrentcalls": case "bulkheadMaxConcurrentCalls": return java.lang.Integer.class; case "bulkheadmaxwaitduration": - case "bulkheadMaxWaitDuration": return java.lang.Integer.class; + case "bulkheadMaxWaitDuration": return java.lang.String.class; case "circuitbreaker": case "circuitBreaker": return java.lang.String.class; case "config": return java.lang.String.class; case "failureratethreshold": case "failureRateThreshold": return java.lang.Float.class; + case "maxwaitdurationinhalfopenstate": + case "maxWaitDurationInHalfOpenState": return java.lang.String.class; case "micrometerenabled": case "micrometerEnabled": return java.lang.Boolean.class; case "minimumnumberofcalls": @@ -124,10 +137,12 @@ public Class getOptionType(String name, boolean ignoreCase) { case "permittedNumberOfCallsInHalfOpenState": return java.lang.Integer.class; case "slidingwindowsize": case "slidingWindowSize": return java.lang.Integer.class; + case "slidingwindowsynchronizationstrategy": + case "slidingWindowSynchronizationStrategy": return java.lang.String.class; case "slidingwindowtype": case "slidingWindowType": return java.lang.String.class; case "slowcalldurationthreshold": - case "slowCallDurationThreshold": return java.lang.Integer.class; + case "slowCallDurationThreshold": return java.lang.String.class; case "slowcallratethreshold": case "slowCallRateThreshold": return java.lang.Float.class; case "throwexceptionwhenhalfopenoropenstate": @@ -135,13 +150,13 @@ public Class getOptionType(String name, boolean ignoreCase) { case "timeoutcancelrunningfuture": case "timeoutCancelRunningFuture": return java.lang.Boolean.class; case "timeoutduration": - case "timeoutDuration": return java.lang.Integer.class; + case "timeoutDuration": return java.lang.String.class; case "timeoutenabled": case "timeoutEnabled": return java.lang.Boolean.class; case "timeoutexecutorservice": case "timeoutExecutorService": return java.lang.String.class; case "waitdurationinopenstate": - case "waitDurationInOpenState": return java.lang.Integer.class; + case "waitDurationInOpenState": return java.lang.String.class; case "writablestacktraceenabled": case "writableStackTraceEnabled": return java.lang.Boolean.class; default: return null; @@ -156,6 +171,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "automaticTransitionFromOpenToHalfOpenEnabled": return target.getAutomaticTransitionFromOpenToHalfOpenEnabled(); case "bulkheadenabled": case "bulkheadEnabled": return target.getBulkheadEnabled(); + case "bulkheadfaircallhandlingenabled": + case "bulkheadFairCallHandlingEnabled": return target.getBulkheadFairCallHandlingEnabled(); case "bulkheadmaxconcurrentcalls": case "bulkheadMaxConcurrentCalls": return target.getBulkheadMaxConcurrentCalls(); case "bulkheadmaxwaitduration": @@ -165,6 +182,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "config": return target.getConfig(); case "failureratethreshold": case "failureRateThreshold": return target.getFailureRateThreshold(); + case "maxwaitdurationinhalfopenstate": + case "maxWaitDurationInHalfOpenState": return target.getMaxWaitDurationInHalfOpenState(); case "micrometerenabled": case "micrometerEnabled": return target.getMicrometerEnabled(); case "minimumnumberofcalls": @@ -173,6 +192,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "permittedNumberOfCallsInHalfOpenState": return target.getPermittedNumberOfCallsInHalfOpenState(); case "slidingwindowsize": case "slidingWindowSize": return target.getSlidingWindowSize(); + case "slidingwindowsynchronizationstrategy": + case "slidingWindowSynchronizationStrategy": return target.getSlidingWindowSynchronizationStrategy(); case "slidingwindowtype": case "slidingWindowType": return target.getSlidingWindowType(); case "slowcalldurationthreshold": diff --git a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json index 144a7868822fc..1acde96827c6f 100644 --- a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json +++ b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json @@ -347,24 +347,27 @@ { "name": "camel.opentelemetry2.traceProcessors", "required": false, "description": "Setting this to true will create new telemetry spans for each Camel custom Processors. Use the excludePattern property to filter out Processors.", "sourceType": "org.apache.camel.main.Otel2ConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": false }, { "name": "camel.resilience4j.automaticTransitionFromOpenToHalfOpenEnabled", "required": false, "description": "Enables automatic transition from OPEN to HALF_OPEN state once the waitDurationInOpenState has passed.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": false, "secret": false }, { "name": "camel.resilience4j.bulkheadEnabled", "required": false, "description": "Whether bulkhead is enabled or not on the circuit breaker.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": false, "secret": false }, + { "name": "camel.resilience4j.bulkheadFairCallHandlingEnabled", "required": false, "description": "Configures whether the bulkhead uses a fair calling strategy. When enabled (default), a fair strategy guarantees the order of incoming requests (FIFO). When disabled, no ordering is guaranteed and may improve throughput.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": true, "secret": false }, { "name": "camel.resilience4j.bulkheadMaxConcurrentCalls", "required": false, "description": "Configures the max amount of concurrent calls the bulkhead will support.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "secret": false }, - { "name": "camel.resilience4j.bulkheadMaxWaitDuration", "required": false, "description": "Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. If bulkhead has space available, entry is guaranteed and immediate. If bulkhead is full, calling threads will contest for space, if it becomes available. maxWaitDuration can be set to 0. Note: for threads running on an event-loop or equivalent (rx computation pool, etc), setting maxWaitDuration to 0 is highly recommended. Blocking an event-loop thread will most likely have a negative effect on application throughput.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "secret": false }, + { "name": "camel.resilience4j.bulkheadMaxWaitDuration", "required": false, "description": "Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. Accepts Camel duration expressions (e.g. 500ms, 1s) or millisecond values. Default is 0 (no waiting).", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.resilience4j.circuitBreaker", "required": false, "description": "Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreaker instance to lookup and use from the registry. When using this, then any other circuit breaker options are not in use.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.resilience4j.config", "required": false, "description": "Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreakerConfig instance to lookup and use from the registry.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.resilience4j.failureRateThreshold", "required": false, "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 be greater than 0 and not greater than 100. Default value is 50 percentage.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "number", "javaType": "java.lang.Float", "defaultValue": "50", "secret": false }, + { "name": "camel.resilience4j.maxWaitDurationInHalfOpenState", "required": false, "description": "Configures the maximum wait duration which controls how long the CircuitBreaker should stay in Half Open state, before it switches to open. Value 0 means circuit breaker will wait in half open state until all permitted calls have been completed. Accepts Camel duration expressions (e.g. 10s, 1m) or millisecond values.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "0", "secret": false }, { "name": "camel.resilience4j.micrometerEnabled", "required": false, "description": "Whether to enable collecting statistics using Micrometer. This requires adding camel-resilience4j-micrometer JAR to the classpath.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": false, "secret": false }, { "name": "camel.resilience4j.minimumNumberOfCalls", "required": false, "description": "Configures 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 10 calls must be recorded, before the failure rate can be calculated. If only 9 calls have been recorded the CircuitBreaker will not transition to open even if all 9 calls have failed. Default minimumNumberOfCalls is 100", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "defaultValue": 100, "secret": false }, { "name": "camel.resilience4j.permittedNumberOfCallsInHalfOpenState", "required": false, "description": "Configures the number of permitted calls when the CircuitBreaker is half open. The size must be greater than 0. Default size is 10.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "defaultValue": 10, "secret": false }, { "name": "camel.resilience4j.slidingWindowSize", "required": false, "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 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 slidingWindowSize seconds are recorded and aggregated. The slidingWindowSize must be greater than 0. The minimumNumberOfCalls must be greater than 0. If the slidingWindowType is COUNT_BASED, the minimumNumberOfCalls cannot be greater than slidingWindowSize . If the slidingWindowType is TIME_BASED, you can pick whatever you want. Default slidingWindowSize is 100.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "defaultValue": 100, "secret": false }, + { "name": "camel.resilience4j.slidingWindowSynchronizationStrategy", "required": false, "description": "Configures the synchronization strategy for the sliding window. LOCK_FREE uses a CAS-based lock-free algorithm for better performance under high concurrency. SYNCHRONIZED uses blocking locks with lower memory allocation.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "enum", "javaType": "java.lang.String", "defaultValue": "SYNCHRONIZED", "secret": false, "enum": [ "LOCK_FREE", "SYNCHRONIZED" ] }, { "name": "camel.resilience4j.slidingWindowType", "required": false, "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 slidingWindowSize seconds are recorded and aggregated. Default slidingWindowType is COUNT_BASED.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "enum", "javaType": "java.lang.String", "defaultValue": "COUNT_BASED", "secret": false, "enum": [ "COUNT_BASED", "TIME_BASED" ] }, - { "name": "camel.resilience4j.slowCallDurationThreshold", "required": false, "description": "Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls percentage. Default value is 60 seconds.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "defaultValue": 60, "secret": false }, + { "name": "camel.resilience4j.slowCallDurationThreshold", "required": false, "description": "Configures the duration threshold above which calls are considered as slow and increase the slow calls percentage. Accepts Camel duration expressions (e.g. 60s, 1m) or millisecond values. Default value is 60 seconds.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "60s", "secret": false }, { "name": "camel.resilience4j.slowCallRateThreshold", "required": false, "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 value is 100 percentage which means that all recorded calls must be slower than slowCallDurationThreshold.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "number", "javaType": "java.lang.Float", "defaultValue": "100", "secret": false }, { "name": "camel.resilience4j.throwExceptionWhenHalfOpenOrOpenState", "required": false, "description": "Whether to throw io.github.resilience4j.circuitbreaker.CallNotPermittedException when the call is rejected due circuit breaker is half open or open.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": false, "secret": false }, { "name": "camel.resilience4j.timeoutCancelRunningFuture", "required": false, "description": "Configures whether cancel is called on the running future. Defaults to true.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": true, "secret": false }, - { "name": "camel.resilience4j.timeoutDuration", "required": false, "description": "Configures the thread execution timeout (millis). Default value is 1000 millis (1 second).", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "defaultValue": 1000, "secret": false }, + { "name": "camel.resilience4j.timeoutDuration", "required": false, "description": "Configures the thread execution timeout. Accepts Camel duration expressions (e.g. 1s, 500ms) or millisecond values. Default value is 1000 millis (1 second).", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "1000", "secret": false }, { "name": "camel.resilience4j.timeoutEnabled", "required": false, "description": "Whether timeout is enabled or not on the circuit breaker. Default is false.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": false, "secret": false }, { "name": "camel.resilience4j.timeoutExecutorService", "required": false, "description": "References to a custom thread pool to use when timeout is enabled (uses ForkJoinPool#commonPool() by default)", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "string", "javaType": "java.lang.String", "secret": false }, - { "name": "camel.resilience4j.waitDurationInOpenState", "required": false, "description": "Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it switches to half open. Default value is 60 seconds.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "defaultValue": 60, "secret": false }, + { "name": "camel.resilience4j.waitDurationInOpenState", "required": false, "description": "Configures the wait duration which specifies how long the CircuitBreaker should stay open, before it switches to half open. Accepts Camel duration expressions (e.g. 60s, 1m) or millisecond values. Default value is 60 seconds.", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "60s", "secret": false }, { "name": "camel.resilience4j.writableStackTraceEnabled", "required": false, "description": "Enables writable stack traces. When set to false, Exception.getStackTrace returns a zero length array. This may be used to reduce log spam when the circuit breaker is open as the cause of the exceptions is already known (the circuit breaker is short-circuiting calls).", "sourceType": "org.apache.camel.main.Resilience4jConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": false, "secret": false }, { "name": "camel.rest.apiComponent", "required": false, "description": "Sets the name of the Camel component to use as the REST API (such as swagger or openapi)", "sourceType": "org.apache.camel.spi.RestConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, { "name": "camel.rest.apiContextPath", "required": false, "description": "Sets a leading API context-path the REST API services will be using. This can be used when using components such as camel-servlet where the deployed web application is deployed using a context-path.", "sourceType": "org.apache.camel.spi.RestConfiguration", "type": "string", "javaType": "java.lang.String", "secret": false }, diff --git a/core/camel-main/src/main/docs/main.adoc b/core/camel-main/src/main/docs/main.adoc index 684b463909f9e..3cd4bcc174eb1 100644 --- a/core/camel-main/src/main/docs/main.adoc +++ b/core/camel-main/src/main/docs/main.adoc @@ -678,31 +678,34 @@ The camel.faulttolerance supports 12 options, which are listed below. === Resilience4j EIP Circuit Breaker configurations -The camel.resilience4j supports 21 options, which are listed below. +The camel.resilience4j supports 24 options, which are listed below. [width="100%",cols="2,5,^1,2",options="header"] |=== | Name | Description | Default | Type | *camel.resilience4j.automaticTransitionFromOpenToHalfOpenEnabled* | Enables automatic transition from OPEN to HALF_OPEN state once the waitDurationInOpenState has passed. | false | Boolean | *camel.resilience4j.bulkheadEnabled* | Whether bulkhead is enabled or not on the circuit breaker. | false | Boolean +| *camel.resilience4j.bulkheadFairCallHandlingEnabled* | Configures whether the bulkhead uses a fair calling strategy. When enabled (default), a fair strategy guarantees the order of incoming requests (FIFO). When disabled, no ordering is guaranteed and may improve throughput. | true | Boolean | *camel.resilience4j.bulkheadMaxConcurrentCalls* | Configures the max amount of concurrent calls the bulkhead will support. | | Integer -| *camel.resilience4j.bulkheadMaxWaitDuration* | Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. If bulkhead has space available, entry is guaranteed and immediate. If bulkhead is full, calling threads will contest for space, if it becomes available. maxWaitDuration can be set to 0. Note: for threads running on an event-loop or equivalent (rx computation pool, etc), setting maxWaitDuration to 0 is highly recommended. Blocking an event-loop thread will most likely have a negative effect on application throughput. | | Integer +| *camel.resilience4j.bulkheadMaxWaitDuration* | Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. Accepts Camel duration expressions (e.g. 500ms, 1s) or millisecond values. Default is 0 (no waiting). | | String | *camel.resilience4j.circuitBreaker* | Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreaker instance to lookup and use from the registry. When using this, then any other circuit breaker options are not in use. | | String | *camel.resilience4j.config* | Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreakerConfig instance to lookup and use from the registry. | | String | *camel.resilience4j.failureRateThreshold* | 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 be greater than 0 and not greater than 100. Default value is 50 percentage. | 50 | Float +| *camel.resilience4j.maxWaitDurationInHalfOpenState* | Configures the maximum wait duration which controls how long the CircuitBreaker should stay in Half Open state, before it switches to open. Value 0 means circuit breaker will wait in half open state until all permitted calls have been completed. Accepts Camel duration expressions (e.g. 10s, 1m) or millisecond values. | 0 | String | *camel.resilience4j.micrometerEnabled* | Whether to enable collecting statistics using Micrometer. This requires adding camel-resilience4j-micrometer JAR to the classpath. | false | Boolean | *camel.resilience4j.minimumNumberOfCalls* | Configures 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 10 calls must be recorded, before the failure rate can be calculated. If only 9 calls have been recorded the CircuitBreaker will not transition to open even if all 9 calls have failed. Default minimumNumberOfCalls is 100 | 100 | Integer | *camel.resilience4j.permittedNumberOfCallsInHalfOpenState* | Configures the number of permitted calls when the CircuitBreaker is half open. The size must be greater than 0. Default size is 10. | 10 | Integer | *camel.resilience4j.slidingWindowSize* | 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 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 slidingWindowSize seconds are recorded and aggregated. The slidingWindowSize must be greater than 0. The minimumNumberOfCalls must be greater than 0. If the slidingWindowType is COUNT_BASED, the minimumNumberOfCalls cannot be greater than slidingWindowSize . If the slidingWindowType is TIME_BASED, you can pick whatever you want. Default slidingWindowSize is 100. | 100 | Integer +| *camel.resilience4j.slidingWindowSynchronizationStrategy* | Configures the synchronization strategy for the sliding window. LOCK_FREE uses a CAS-based lock-free algorithm for better performance under high concurrency. SYNCHRONIZED uses blocking locks with lower memory allocation. | SYNCHRONIZED | String | *camel.resilience4j.slidingWindowType* | 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 slidingWindowSize seconds are recorded and aggregated. Default slidingWindowType is COUNT_BASED. | COUNT_BASED | String -| *camel.resilience4j.slowCallDurationThreshold* | Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls percentage. Default value is 60 seconds. | 60 | Integer +| *camel.resilience4j.slowCallDurationThreshold* | Configures the duration threshold above which calls are considered as slow and increase the slow calls percentage. Accepts Camel duration expressions (e.g. 60s, 1m) or millisecond values. Default value is 60 seconds. | 60s | String | *camel.resilience4j.slowCallRateThreshold* | 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 value is 100 percentage which means that all recorded calls must be slower than slowCallDurationThreshold. | 100 | Float | *camel.resilience4j.throwExceptionWhenHalfOpenOrOpenState* | Whether to throw io.github.resilience4j.circuitbreaker.CallNotPermittedException when the call is rejected due circuit breaker is half open or open. | false | Boolean | *camel.resilience4j.timeoutCancelRunningFuture* | Configures whether cancel is called on the running future. Defaults to true. | true | Boolean -| *camel.resilience4j.timeoutDuration* | Configures the thread execution timeout (millis). Default value is 1000 millis (1 second). | 1000 | Integer +| *camel.resilience4j.timeoutDuration* | Configures the thread execution timeout. Accepts Camel duration expressions (e.g. 1s, 500ms) or millisecond values. Default value is 1000 millis (1 second). | 1000 | String | *camel.resilience4j.timeoutEnabled* | Whether timeout is enabled or not on the circuit breaker. Default is false. | false | Boolean | *camel.resilience4j.timeoutExecutorService* | References to a custom thread pool to use when timeout is enabled (uses ForkJoinPool#commonPool() by default) | | String -| *camel.resilience4j.waitDurationInOpenState* | Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it switches to half open. Default value is 60 seconds. | 60 | Integer +| *camel.resilience4j.waitDurationInOpenState* | Configures the wait duration which specifies how long the CircuitBreaker should stay open, before it switches to half open. Accepts Camel duration expressions (e.g. 60s, 1m) or millisecond values. Default value is 60 seconds. | 60s | String | *camel.resilience4j.writableStackTraceEnabled* | Enables writable stack traces. When set to false, Exception.getStackTrace returns a zero length array. This may be used to reduce log spam when the circuit breaker is open as the cause of the exceptions is already known (the circuit breaker is short-circuiting calls). | false | Boolean |=== diff --git a/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java index 3f67431cbfb86..3c79d34b7f91a 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java @@ -45,26 +45,32 @@ public class Resilience4jConfigurationProperties implements BootstrapCloseable { @Metadata(defaultValue = "100") private Integer minimumNumberOfCalls; private Boolean writableStackTraceEnabled; - @Metadata(defaultValue = "60") - private Integer waitDurationInOpenState; + @Metadata(defaultValue = "60s") + private String waitDurationInOpenState; private Boolean automaticTransitionFromOpenToHalfOpenEnabled; @Metadata(defaultValue = "100") private Float slowCallRateThreshold; - @Metadata(defaultValue = "60") - private Integer slowCallDurationThreshold; + @Metadata(defaultValue = "60s") + private String slowCallDurationThreshold; @Metadata(defaultValue = "false") private Boolean bulkheadEnabled; private Integer bulkheadMaxConcurrentCalls; - private Integer bulkheadMaxWaitDuration; + private String bulkheadMaxWaitDuration; @Metadata(defaultValue = "false") private Boolean timeoutEnabled; private String timeoutExecutorService; @Metadata(defaultValue = "1000") - private Integer timeoutDuration; + private String timeoutDuration; @Metadata(defaultValue = "true") private Boolean timeoutCancelRunningFuture; @Metadata(defaultValue = "false") private Boolean micrometerEnabled; + @Metadata(defaultValue = "SYNCHRONIZED", enums = "LOCK_FREE,SYNCHRONIZED") + private String slidingWindowSynchronizationStrategy; + @Metadata(defaultValue = "0") + private String maxWaitDurationInHalfOpenState; + @Metadata(defaultValue = "true") + private Boolean bulkheadFairCallHandlingEnabled; public Resilience4jConfigurationProperties(MainConfigurationProperties parent) { this.parent = parent; @@ -215,15 +221,15 @@ public void setWritableStackTraceEnabled(Boolean writableStackTraceEnabled) { this.writableStackTraceEnabled = writableStackTraceEnabled; } - public Integer getWaitDurationInOpenState() { + public String getWaitDurationInOpenState() { return waitDurationInOpenState; } /** - * Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it - * switches to half open. Default value is 60 seconds. + * Configures the wait duration which specifies how long the CircuitBreaker should stay open, before it switches to + * half open. Accepts Camel duration expressions (e.g. 60s, 1m) or millisecond values. Default value is 60 seconds. */ - public void setWaitDurationInOpenState(Integer waitDurationInOpenState) { + public void setWaitDurationInOpenState(String waitDurationInOpenState) { this.waitDurationInOpenState = waitDurationInOpenState; } @@ -254,15 +260,15 @@ public void setSlowCallRateThreshold(Float slowCallRateThreshold) { this.slowCallRateThreshold = slowCallRateThreshold; } - public Integer getSlowCallDurationThreshold() { + public String getSlowCallDurationThreshold() { return slowCallDurationThreshold; } /** - * Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls - * percentage. Default value is 60 seconds. + * Configures the duration threshold above which calls are considered as slow and increase the slow calls + * percentage. Accepts Camel duration expressions (e.g. 60s, 1m) or millisecond values. Default value is 60 seconds. */ - public void setSlowCallDurationThreshold(Integer slowCallDurationThreshold) { + public void setSlowCallDurationThreshold(String slowCallDurationThreshold) { this.slowCallDurationThreshold = slowCallDurationThreshold; } @@ -288,20 +294,15 @@ public void setBulkheadMaxConcurrentCalls(Integer bulkheadMaxConcurrentCalls) { this.bulkheadMaxConcurrentCalls = bulkheadMaxConcurrentCalls; } - public Integer getBulkheadMaxWaitDuration() { + public String getBulkheadMaxWaitDuration() { return bulkheadMaxWaitDuration; } /** - * Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. If bulkhead has - * space available, entry is guaranteed and immediate. If bulkhead is full, calling threads will contest for space, - * if it becomes available. maxWaitDuration can be set to 0. - *

- * Note: for threads running on an event-loop or equivalent (rx computation pool, etc), setting maxWaitDuration to 0 - * is highly recommended. Blocking an event-loop thread will most likely have a negative effect on application - * throughput. + * Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. Accepts Camel + * duration expressions (e.g. 500ms, 1s) or millisecond values. Default is 0 (no waiting). */ - public void setBulkheadMaxWaitDuration(Integer bulkheadMaxWaitDuration) { + public void setBulkheadMaxWaitDuration(String bulkheadMaxWaitDuration) { this.bulkheadMaxWaitDuration = bulkheadMaxWaitDuration; } @@ -328,14 +329,15 @@ public void setTimeoutExecutorService(String timeoutExecutorService) { this.timeoutExecutorService = timeoutExecutorService; } - public Integer getTimeoutDuration() { + public String getTimeoutDuration() { return timeoutDuration; } /** - * Configures the thread execution timeout (millis). Default value is 1000 millis (1 second). + * Configures the thread execution timeout. Accepts Camel duration expressions (e.g. 1s, 500ms) or millisecond + * values. Default value is 1000 millis (1 second). */ - public void setTimeoutDuration(Integer timeoutDuration) { + public void setTimeoutDuration(String timeoutDuration) { this.timeoutDuration = timeoutDuration; } @@ -362,6 +364,43 @@ public void setMicrometerEnabled(Boolean micrometerEnabled) { this.micrometerEnabled = micrometerEnabled; } + public String getSlidingWindowSynchronizationStrategy() { + return slidingWindowSynchronizationStrategy; + } + + /** + * Configures the synchronization strategy for the sliding window. LOCK_FREE uses a CAS-based lock-free algorithm + * for better performance under high concurrency. SYNCHRONIZED uses blocking locks with lower memory allocation. + */ + public void setSlidingWindowSynchronizationStrategy(String slidingWindowSynchronizationStrategy) { + this.slidingWindowSynchronizationStrategy = slidingWindowSynchronizationStrategy; + } + + public String getMaxWaitDurationInHalfOpenState() { + return maxWaitDurationInHalfOpenState; + } + + /** + * Configures the maximum wait duration which controls how long the CircuitBreaker should stay in Half Open state, + * before it switches to open. Value 0 means circuit breaker will wait in half open state until all permitted calls + * have been completed. Accepts Camel duration expressions (e.g. 10s, 1m) or millisecond values. + */ + public void setMaxWaitDurationInHalfOpenState(String maxWaitDurationInHalfOpenState) { + this.maxWaitDurationInHalfOpenState = maxWaitDurationInHalfOpenState; + } + + public Boolean getBulkheadFairCallHandlingEnabled() { + return bulkheadFairCallHandlingEnabled; + } + + /** + * Configures whether the bulkhead uses a fair calling strategy. When enabled (default), a fair strategy guarantees + * the order of incoming requests (FIFO). When disabled, no ordering is guaranteed and may improve throughput. + */ + public void setBulkheadFairCallHandlingEnabled(Boolean bulkheadFairCallHandlingEnabled) { + this.bulkheadFairCallHandlingEnabled = bulkheadFairCallHandlingEnabled; + } + /** * Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreaker instance to lookup and use from the * registry. When using this, then any other circuit breaker options are not in use. @@ -471,10 +510,10 @@ public Resilience4jConfigurationProperties withWritableStackTraceEnabled(Boolean } /** - * Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it - * switches to half open. Default value is 60 seconds. + * Configures the wait duration which specifies how long the CircuitBreaker should stay open, before it switches to + * half open. Accepts Camel duration expressions (e.g. 60s, 1m) or millisecond values. Default value is 60 seconds. */ - public Resilience4jConfigurationProperties withWaitDurationInOpenState(Integer waitDurationInOpenState) { + public Resilience4jConfigurationProperties withWaitDurationInOpenState(String waitDurationInOpenState) { this.waitDurationInOpenState = waitDurationInOpenState; return this; } @@ -499,10 +538,10 @@ public Resilience4jConfigurationProperties withSlowCallRateThreshold(Float slowC } /** - * Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls - * percentage. Default value is 60 seconds. + * Configures the duration threshold above which calls are considered as slow and increase the slow calls + * percentage. Accepts Camel duration expressions (e.g. 60s, 1m) or millisecond values. Default value is 60 seconds. */ - public Resilience4jConfigurationProperties withSlowCallDurationThreshold(Integer slowCallDurationThreshold) { + public Resilience4jConfigurationProperties withSlowCallDurationThreshold(String slowCallDurationThreshold) { this.slowCallDurationThreshold = slowCallDurationThreshold; return this; } @@ -524,15 +563,10 @@ public Resilience4jConfigurationProperties withBulkheadMaxConcurrentCalls(Intege } /** - * Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. If bulkhead has - * space available, entry is guaranteed and immediate. If bulkhead is full, calling threads will contest for space, - * if it becomes available. maxWaitDuration can be set to 0. - *

- * Note: for threads running on an event-loop or equivalent (rx computation pool, etc), setting maxWaitDuration to 0 - * is highly recommended. Blocking an event-loop thread will most likely have a negative effect on application - * throughput. + * Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. Accepts Camel + * duration expressions (e.g. 500ms, 1s) or millisecond values. Default is 0 (no waiting). */ - public Resilience4jConfigurationProperties withBulkheadMaxWaitDuration(Integer bulkheadMaxWaitDuration) { + public Resilience4jConfigurationProperties withBulkheadMaxWaitDuration(String bulkheadMaxWaitDuration) { this.bulkheadMaxWaitDuration = bulkheadMaxWaitDuration; return this; } @@ -555,9 +589,10 @@ public Resilience4jConfigurationProperties withTimeoutExecutorServiceRef(String } /** - * Configures the thread execution timeout (millis). Default value is 1000 millis (1 second). + * Configures the thread execution timeout. Accepts Camel duration expressions (e.g. 1s, 500ms) or millisecond + * values. Default value is 1000 millis (1 second). */ - public Resilience4jConfigurationProperties withTimeoutDuration(Integer timeoutDuration) { + public Resilience4jConfigurationProperties withTimeoutDuration(String timeoutDuration) { this.timeoutDuration = timeoutDuration; return this; } @@ -579,4 +614,35 @@ public Resilience4jConfigurationProperties withMicrometerEnabled(Boolean microme return this; } + /** + * Configures the synchronization strategy for the sliding window. LOCK_FREE uses a CAS-based lock-free algorithm + * for better performance under high concurrency. SYNCHRONIZED uses blocking locks with lower memory allocation. + */ + public Resilience4jConfigurationProperties withSlidingWindowSynchronizationStrategy( + String slidingWindowSynchronizationStrategy) { + this.slidingWindowSynchronizationStrategy = slidingWindowSynchronizationStrategy; + return this; + } + + /** + * Configures the maximum wait duration which controls how long the CircuitBreaker should stay in Half Open state, + * before it switches to open. Value 0 means circuit breaker will wait in half open state until all permitted calls + * have been completed. Accepts Camel duration expressions (e.g. 10s, 1m) or millisecond values. + */ + public Resilience4jConfigurationProperties withMaxWaitDurationInHalfOpenState( + String maxWaitDurationInHalfOpenState) { + this.maxWaitDurationInHalfOpenState = maxWaitDurationInHalfOpenState; + return this; + } + + /** + * Configures whether the bulkhead uses a fair calling strategy. When enabled (default), a fair strategy guarantees + * the order of incoming requests (FIFO). When disabled, no ordering is guaranteed and may improve throughput. + */ + public Resilience4jConfigurationProperties withBulkheadFairCallHandlingEnabled( + Boolean bulkheadFairCallHandlingEnabled) { + this.bulkheadFairCallHandlingEnabled = bulkheadFairCallHandlingEnabled; + return this; + } + } diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java index c54e2fd73f631..4bd796100d350 100644 --- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java +++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java @@ -796,15 +796,18 @@ protected AttributeHandler resili return (def, key, val) -> switch (key) { case "automaticTransitionFromOpenToHalfOpenEnabled": def.setAutomaticTransitionFromOpenToHalfOpenEnabled(val); yield true; case "bulkheadEnabled": def.setBulkheadEnabled(val); yield true; + case "bulkheadFairCallHandlingEnabled": def.setBulkheadFairCallHandlingEnabled(val); yield true; case "bulkheadMaxConcurrentCalls": def.setBulkheadMaxConcurrentCalls(val); yield true; case "bulkheadMaxWaitDuration": def.setBulkheadMaxWaitDuration(val); yield true; case "circuitBreaker": def.setCircuitBreaker(val); yield true; case "config": def.setConfig(val); yield true; case "failureRateThreshold": def.setFailureRateThreshold(val); yield true; + case "maxWaitDurationInHalfOpenState": def.setMaxWaitDurationInHalfOpenState(val); yield true; case "micrometerEnabled": def.setMicrometerEnabled(val); yield true; case "minimumNumberOfCalls": def.setMinimumNumberOfCalls(val); yield true; case "permittedNumberOfCallsInHalfOpenState": def.setPermittedNumberOfCallsInHalfOpenState(val); yield true; case "slidingWindowSize": def.setSlidingWindowSize(val); yield true; + case "slidingWindowSynchronizationStrategy": def.setSlidingWindowSynchronizationStrategy(val); yield true; case "slidingWindowType": def.setSlidingWindowType(val); yield true; case "slowCallDurationThreshold": def.setSlowCallDurationThreshold(val); yield true; case "slowCallRateThreshold": def.setSlowCallRateThreshold(val); yield true; diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java index 0a626c45172af..f60eb2643f496 100644 --- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java +++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java @@ -1512,15 +1512,18 @@ protected void doWriteResilience4jConfigurationCommonAttributes(Resilience4jConf doWriteAttribute("throwExceptionWhenHalfOpenOrOpenState", def.getThrowExceptionWhenHalfOpenOrOpenState(), "false"); doWriteAttribute("slidingWindowSize", def.getSlidingWindowSize(), "100"); doWriteAttribute("slidingWindowType", def.getSlidingWindowType(), "COUNT_BASED"); + doWriteAttribute("slidingWindowSynchronizationStrategy", def.getSlidingWindowSynchronizationStrategy(), "SYNCHRONIZED"); doWriteAttribute("minimumNumberOfCalls", def.getMinimumNumberOfCalls(), "100"); doWriteAttribute("writableStackTraceEnabled", def.getWritableStackTraceEnabled(), "true"); - doWriteAttribute("waitDurationInOpenState", def.getWaitDurationInOpenState(), "60"); + doWriteAttribute("waitDurationInOpenState", def.getWaitDurationInOpenState(), "60000"); doWriteAttribute("automaticTransitionFromOpenToHalfOpenEnabled", def.getAutomaticTransitionFromOpenToHalfOpenEnabled(), "false"); + doWriteAttribute("maxWaitDurationInHalfOpenState", def.getMaxWaitDurationInHalfOpenState(), "0"); doWriteAttribute("slowCallRateThreshold", def.getSlowCallRateThreshold(), "100"); - doWriteAttribute("slowCallDurationThreshold", def.getSlowCallDurationThreshold(), "60"); + doWriteAttribute("slowCallDurationThreshold", def.getSlowCallDurationThreshold(), "60000"); doWriteAttribute("bulkheadEnabled", def.getBulkheadEnabled(), "false"); doWriteAttribute("bulkheadMaxConcurrentCalls", def.getBulkheadMaxConcurrentCalls(), "25"); doWriteAttribute("bulkheadMaxWaitDuration", def.getBulkheadMaxWaitDuration(), "0"); + doWriteAttribute("bulkheadFairCallHandlingEnabled", def.getBulkheadFairCallHandlingEnabled(), "true"); doWriteAttribute("timeoutEnabled", def.getTimeoutEnabled(), "false"); doWriteAttribute("timeoutExecutorService", def.getTimeoutExecutorService(), null); doWriteAttribute("timeoutDuration", def.getTimeoutDuration(), "1000"); diff --git a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/YamlModelWriter.java b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/YamlModelWriter.java index 484287ecd0b4a..dd039a8c9a707 100644 --- a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/YamlModelWriter.java +++ b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/YamlModelWriter.java @@ -1507,15 +1507,18 @@ protected void doWriteResilience4jConfigurationCommonAttributes(JsonObject jo, R doWriteAttribute(jo, "throwExceptionWhenHalfOpenOrOpenState", def.getThrowExceptionWhenHalfOpenOrOpenState(), "false"); doWriteAttribute(jo, "slidingWindowSize", def.getSlidingWindowSize(), "100"); doWriteAttribute(jo, "slidingWindowType", def.getSlidingWindowType(), "COUNT_BASED"); + doWriteAttribute(jo, "slidingWindowSynchronizationStrategy", def.getSlidingWindowSynchronizationStrategy(), "SYNCHRONIZED"); doWriteAttribute(jo, "minimumNumberOfCalls", def.getMinimumNumberOfCalls(), "100"); doWriteAttribute(jo, "writableStackTraceEnabled", def.getWritableStackTraceEnabled(), "true"); - doWriteAttribute(jo, "waitDurationInOpenState", def.getWaitDurationInOpenState(), "60"); + doWriteAttribute(jo, "waitDurationInOpenState", def.getWaitDurationInOpenState(), "60000"); doWriteAttribute(jo, "automaticTransitionFromOpenToHalfOpenEnabled", def.getAutomaticTransitionFromOpenToHalfOpenEnabled(), "false"); + doWriteAttribute(jo, "maxWaitDurationInHalfOpenState", def.getMaxWaitDurationInHalfOpenState(), "0"); doWriteAttribute(jo, "slowCallRateThreshold", def.getSlowCallRateThreshold(), "100"); - doWriteAttribute(jo, "slowCallDurationThreshold", def.getSlowCallDurationThreshold(), "60"); + doWriteAttribute(jo, "slowCallDurationThreshold", def.getSlowCallDurationThreshold(), "60000"); doWriteAttribute(jo, "bulkheadEnabled", def.getBulkheadEnabled(), "false"); doWriteAttribute(jo, "bulkheadMaxConcurrentCalls", def.getBulkheadMaxConcurrentCalls(), "25"); doWriteAttribute(jo, "bulkheadMaxWaitDuration", def.getBulkheadMaxWaitDuration(), "0"); + doWriteAttribute(jo, "bulkheadFairCallHandlingEnabled", def.getBulkheadFairCallHandlingEnabled(), "true"); doWriteAttribute(jo, "timeoutEnabled", def.getTimeoutEnabled(), "false"); doWriteAttribute(jo, "timeoutExecutorService", def.getTimeoutExecutorService(), null); doWriteAttribute(jo, "timeoutDuration", def.getTimeoutDuration(), "1000"); diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc index 79f816747078c..2197a48bb5fb8 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc @@ -772,3 +772,62 @@ add `precision = 0` explicitly to your `@DataField` annotation. The `transformerFactoryConfigurationStrategy` option is now applied on all factory creation paths. Previously on `xslt-saxon` it was never invoked, and on plain `xslt` it was only invoked when `transformerFactoryClass` was explicitly set. + +=== Circuit Breaker EIP - onFallbackViaNetwork deprecated + +The `onFallbackViaNetwork()` DSL method and the `fallbackViaNetwork` option on `onFallback` have been +deprecated for removal. This was a Hystrix-era concept that has never been supported by any current +circuit breaker implementation — both `camel-resilience4j` and `camel-microprofile-fault-tolerance` +throw `UnsupportedOperationException` at route initialization when it is enabled. +Use `onFallback()` instead. + +=== camel-resilience4j - Duration options now use Camel duration format + +The following Resilience4j configuration options now use `java.time.Duration` type instead of plain integers, +and accept Camel duration expressions (e.g. `60s`, `1m`, `PT1M`) as well as plain millisecond values: + +- `waitDurationInOpenState` — previously accepted seconds (default `60`), now accepts millis or duration strings (default `60000` or `60s`) +- `slowCallDurationThreshold` — previously accepted seconds (default `60`), now accepts millis or duration strings (default `60000` or `60s`) +- `timeoutDuration` — unchanged (was already millis, default `1000`) +- `bulkheadMaxWaitDuration` — unchanged (was already millis, default `0`) + +If you configured `waitDurationInOpenState` or `slowCallDurationThreshold` with a plain integer meaning seconds, +you must update the value to use a duration suffix (e.g. `60s`) or convert to milliseconds (e.g. `60000`). + +*Java DSL:* +[source,java] +---- +// Before (seconds): +.waitDurationInOpenState(60) + +// After (millis): +.waitDurationInOpenState(60000) + +// Or using duration string (preferred): +.waitDurationInOpenState("60s") +---- + +The `int` overloads for `waitDurationInOpenState(int)`, `slowCallDurationThreshold(int)`, +`timeoutDuration(int)`, and `bulkheadMaxWaitDuration(int)` have been deprecated. Use the +`String` overloads with Camel duration expressions instead. + +*Application properties (camel-main, Spring Boot, Quarkus):* + +If you configure circuit breaker settings via `application.properties`, the same migration applies: +[source,properties] +---- +# Before (seconds): +camel.resilience4j.waitDurationInOpenState = 60 + +# After (duration string): +camel.resilience4j.waitDurationInOpenState = 60s + +# Or milliseconds: +camel.resilience4j.waitDurationInOpenState = 60000 +---- + +=== camel-resilience4j - Vavr dependency removed + +The `io.vavr:vavr` and `io.vavr:vavr-match` runtime dependencies have been removed from +`camel-resilience4j`. The single internal usage of Vavr's `Try` monad has been replaced with a +plain try-catch. This eliminates two transitive runtime JARs. No user-facing behavior change. 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 bd73dd58e6081..41b495835e323 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 @@ -10622,7 +10622,7 @@ protected boolean setProperty(OnExceptionDefinition target, String propertyKey, deprecated = false, properties = { @YamlProperty(name = "description", type = "string", description = "The description for this node", displayName = "Description"), - @YamlProperty(name = "fallbackViaNetwork", type = "boolean", defaultValue = "false", description = "Whether the fallback goes over the network. If so, the fallback is executed on a separate thread-pool to avoid exhausting the main thread-pool.", displayName = "Fallback Via Network"), + @YamlProperty(name = "fallbackViaNetwork", type = "boolean", deprecated = true, defaultValue = "false", description = "Whether the fallback goes over the network. If so, the fallback is executed on a separate thread-pool to avoid exhausting the main thread-pool.", displayName = "Fallback Via Network"), @YamlProperty(name = "id", type = "string", description = "The id of this node", displayName = "Id"), @YamlProperty(name = "note", type = "string", description = "The note for this node", displayName = "Note"), @YamlProperty(name = "steps", type = "array:org.apache.camel.model.ProcessorDefinition") @@ -13886,27 +13886,30 @@ protected boolean setProperty(ResequenceDefinition target, String propertyKey, properties = { @YamlProperty(name = "automaticTransitionFromOpenToHalfOpenEnabled", type = "boolean", defaultValue = "false", description = "Enables automatic transition from OPEN to HALF_OPEN state once the waitDurationInOpenState has passed.", displayName = "Automatic Transition From Open To Half Open Enabled"), @YamlProperty(name = "bulkheadEnabled", type = "boolean", defaultValue = "false", description = "Whether bulkhead is enabled or not on the circuit breaker.", displayName = "Bulkhead Enabled"), + @YamlProperty(name = "bulkheadFairCallHandlingEnabled", type = "boolean", defaultValue = "true", description = "Configures whether the bulkhead uses a fair calling strategy. When enabled (default), a fair strategy guarantees the order of incoming requests (FIFO). When disabled, no ordering is guaranteed and may improve throughput.", displayName = "Bulkhead Fair Call Handling Enabled"), @YamlProperty(name = "bulkheadMaxConcurrentCalls", type = "number", defaultValue = "25", description = "Configures the max amount of concurrent calls the bulkhead will support.", displayName = "Bulkhead Max Concurrent Calls"), - @YamlProperty(name = "bulkheadMaxWaitDuration", type = "number", defaultValue = "0", description = "Configures a maximum amount of time which the calling thread will wait to enter the bulkhead.", displayName = "Bulkhead Max Wait Duration"), + @YamlProperty(name = "bulkheadMaxWaitDuration", type = "string", defaultValue = "0", description = "Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. The default is 0 (no waiting).", displayName = "Bulkhead Max Wait Duration"), @YamlProperty(name = "circuitBreaker", type = "string", description = "Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreaker instance to lookup and use from the registry. When using this, then any other circuit breaker options are not in use.", displayName = "Circuit Breaker"), @YamlProperty(name = "config", type = "string", description = "Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreakerConfig instance to lookup and use from the registry.", displayName = "Config"), @YamlProperty(name = "failureRateThreshold", type = "number", 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.", displayName = "Failure Rate Threshold"), @YamlProperty(name = "id", type = "string", description = "The id of this node", displayName = "Id"), @YamlProperty(name = "ignoreException", type = "array:string", description = "Configure a list of exceptions that are ignored and neither count as a failure nor success. Any exception matching or inheriting from one of the list will not count as a failure nor success, even if the exception is part of recordExceptions.", displayName = "Ignore Exception"), - @YamlProperty(name = "micrometerEnabled", type = "boolean", defaultValue = "false", description = "Whether to enable collecting statistics using Micrometer. This requires adding camel-resilience4j-micrometer JAR to the classpath.", displayName = "Micrometer Enabled"), + @YamlProperty(name = "maxWaitDurationInHalfOpenState", type = "string", defaultValue = "0", description = "Configures the maximum wait duration which controls how long the CircuitBreaker should stay in Half Open state, before it switches to open. Value 0 means circuit breaker will wait in half open state until all permitted calls have been completed.", displayName = "Max Wait Duration In Half Open State"), + @YamlProperty(name = "micrometerEnabled", type = "boolean", defaultValue = "false", description = "Whether to enable collecting statistics using Micrometer for all circuit breaker instances. This is a global setting (configure via camel.resilience4j.micrometerEnabled=true) and requires adding camel-resilience4j-micrometer JAR to the classpath.", displayName = "Micrometer Enabled"), @YamlProperty(name = "minimumNumberOfCalls", type = "number", defaultValue = "100", description = "Configures the minimum number of calls which are required (per sliding window period) before the CircuitBreaker can calculate the error rate.", displayName = "Minimum Number Of Calls"), @YamlProperty(name = "permittedNumberOfCallsInHalfOpenState", type = "number", defaultValue = "10", description = "Configures the number of permitted calls when the CircuitBreaker is half open.", displayName = "Permitted Number Of Calls In Half Open State"), @YamlProperty(name = "recordException", type = "array:string", description = "Configure a list of exceptions that are recorded as a failure and thus increase the failure rate. Any exception matching or inheriting from one of the list counts as a failure, unless explicitly ignored via ignoreExceptions.", displayName = "Record Exception"), @YamlProperty(name = "slidingWindowSize", type = "number", defaultValue = "100", description = "Configures the size 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.", displayName = "Sliding Window Size"), + @YamlProperty(name = "slidingWindowSynchronizationStrategy", type = "enum:LOCK_FREE,SYNCHRONIZED", defaultValue = "SYNCHRONIZED", description = "Configures the synchronization strategy for the sliding window. LOCK_FREE uses a CAS-based lock-free algorithm for better performance under high concurrency. SYNCHRONIZED uses blocking locks with lower memory allocation.", displayName = "Sliding Window Synchronization Strategy"), @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.", displayName = "Sliding Window Type"), - @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.", displayName = "Slow Call Duration Threshold"), + @YamlProperty(name = "slowCallDurationThreshold", type = "string", defaultValue = "60000", description = "Configures the duration threshold above which calls are considered as slow and increase the slow calls percentage. The default 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. When the percentage of slow calls is equal or greater the threshold, the CircuitBreaker transitions to open and starts short-circuiting calls.", displayName = "Slow Call Rate Threshold"), @YamlProperty(name = "throwExceptionWhenHalfOpenOrOpenState", type = "boolean", defaultValue = "false", description = "Whether to throw io.github.resilience4j.circuitbreaker.CallNotPermittedException when the call is rejected because the circuit breaker is half open or open.", displayName = "Throw Exception When Half Open Or Open State"), @YamlProperty(name = "timeoutCancelRunningFuture", type = "boolean", defaultValue = "true", 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 = "timeoutDuration", type = "string", defaultValue = "1000", description = "Configures the thread execution timeout. Default value is 1 second.", displayName = "Timeout Duration"), @YamlProperty(name = "timeoutEnabled", type = "boolean", defaultValue = "false", description = "Whether timeout is enabled or not on the circuit breaker.", displayName = "Timeout Enabled"), @YamlProperty(name = "timeoutExecutorService", type = "string", description = "References to a custom thread pool to use when timeout is enabled (uses ForkJoinPool.commonPool() by default).", displayName = "Timeout Executor Service"), - @YamlProperty(name = "waitDurationInOpenState", type = "number", defaultValue = "60", description = "Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it switches to half open.", displayName = "Wait Duration In Open State"), + @YamlProperty(name = "waitDurationInOpenState", type = "string", defaultValue = "60000", description = "Configures the wait duration which specifies how long the CircuitBreaker should stay open, before it switches to half open. The default is 60 seconds.", displayName = "Wait Duration In Open State"), @YamlProperty(name = "writableStackTraceEnabled", type = "boolean", defaultValue = "true", description = "Enables writable stack traces. When set to false, Exception.getStackTrace returns a zero length array. This may be used to reduce log spam when the circuit breaker is open.", displayName = "Writable Stack Trace Enabled") } ) @@ -13935,6 +13938,11 @@ protected boolean setProperty(Resilience4jConfigurationDefinition target, target.setBulkheadEnabled(val); break; } + case "bulkheadFairCallHandlingEnabled": { + String val = asText(node); + target.setBulkheadFairCallHandlingEnabled(val); + break; + } case "bulkheadMaxConcurrentCalls": { String val = asText(node); target.setBulkheadMaxConcurrentCalls(val); @@ -13970,6 +13978,11 @@ protected boolean setProperty(Resilience4jConfigurationDefinition target, target.setIgnoreExceptions(val); break; } + case "maxWaitDurationInHalfOpenState": { + String val = asText(node); + target.setMaxWaitDurationInHalfOpenState(val); + break; + } case "micrometerEnabled": { String val = asText(node); target.setMicrometerEnabled(val); @@ -13995,6 +14008,11 @@ protected boolean setProperty(Resilience4jConfigurationDefinition target, target.setSlidingWindowSize(val); break; } + case "slidingWindowSynchronizationStrategy": { + String val = asText(node); + target.setSlidingWindowSynchronizationStrategy(val); + break; + } case "slidingWindowType": { String val = asText(node); target.setSlidingWindowType(val); diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-canonical.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-canonical.json index a35878691db28..8d2f166078e8e 100644 --- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-canonical.json +++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-canonical.json @@ -2555,6 +2555,7 @@ "type" : "boolean", "title" : "Fallback Via Network", "description" : "Whether the fallback goes over the network. If so, the fallback is executed on a separate thread-pool to avoid exhausting the main thread-pool.", + "deprecated" : true, "default" : false }, "id" : { @@ -3619,6 +3620,12 @@ "description" : "Whether bulkhead is enabled or not on the circuit breaker.", "default" : false }, + "bulkheadFairCallHandlingEnabled" : { + "type" : "boolean", + "title" : "Bulkhead Fair Call Handling Enabled", + "description" : "Configures whether the bulkhead uses a fair calling strategy. When enabled (default), a fair strategy guarantees the order of incoming requests (FIFO). When disabled, no ordering is guaranteed and may improve throughput.", + "default" : true + }, "bulkheadMaxConcurrentCalls" : { "type" : "number", "title" : "Bulkhead Max Concurrent Calls", @@ -3626,10 +3633,10 @@ "default" : 25 }, "bulkheadMaxWaitDuration" : { - "type" : "number", + "type" : "string", "title" : "Bulkhead Max Wait Duration", - "description" : "Configures a maximum amount of time which the calling thread will wait to enter the bulkhead.", - "default" : 0 + "description" : "Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. The default is 0 (no waiting).", + "default" : "0" }, "circuitBreaker" : { "type" : "string", @@ -3660,10 +3667,16 @@ "type" : "string" } }, + "maxWaitDurationInHalfOpenState" : { + "type" : "string", + "title" : "Max Wait Duration In Half Open State", + "description" : "Configures the maximum wait duration which controls how long the CircuitBreaker should stay in Half Open state, before it switches to open. Value 0 means circuit breaker will wait in half open state until all permitted calls have been completed.", + "default" : "0" + }, "micrometerEnabled" : { "type" : "boolean", "title" : "Micrometer Enabled", - "description" : "Whether to enable collecting statistics using Micrometer. This requires adding camel-resilience4j-micrometer JAR to the classpath.", + "description" : "Whether to enable collecting statistics using Micrometer for all circuit breaker instances. This is a global setting (configure via camel.resilience4j.micrometerEnabled=true) and requires adding camel-resilience4j-micrometer JAR to the classpath.", "default" : false }, "minimumNumberOfCalls" : { @@ -3692,6 +3705,13 @@ "description" : "Configures the size 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.", "default" : 100 }, + "slidingWindowSynchronizationStrategy" : { + "type" : "string", + "title" : "Sliding Window Synchronization Strategy", + "description" : "Configures the synchronization strategy for the sliding window. LOCK_FREE uses a CAS-based lock-free algorithm for better performance under high concurrency. SYNCHRONIZED uses blocking locks with lower memory allocation.", + "default" : "SYNCHRONIZED", + "enum" : [ "LOCK_FREE", "SYNCHRONIZED" ] + }, "slidingWindowType" : { "type" : "string", "title" : "Sliding Window Type", @@ -3700,10 +3720,10 @@ "enum" : [ "TIME_BASED", "COUNT_BASED" ] }, "slowCallDurationThreshold" : { - "type" : "number", + "type" : "string", "title" : "Slow Call Duration Threshold", - "description" : "Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls percentage.", - "default" : 60 + "description" : "Configures the duration threshold above which calls are considered as slow and increase the slow calls percentage. The default is 60 seconds.", + "default" : "60000" }, "slowCallRateThreshold" : { "type" : "number", @@ -3724,10 +3744,10 @@ "default" : true }, "timeoutDuration" : { - "type" : "number", + "type" : "string", "title" : "Timeout Duration", "description" : "Configures the thread execution timeout. Default value is 1 second.", - "default" : 1000 + "default" : "1000" }, "timeoutEnabled" : { "type" : "boolean", @@ -3741,10 +3761,10 @@ "description" : "References to a custom thread pool to use when timeout is enabled (uses ForkJoinPool.commonPool() by default)." }, "waitDurationInOpenState" : { - "type" : "number", + "type" : "string", "title" : "Wait Duration In Open State", - "description" : "Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it switches to half open.", - "default" : 60 + "description" : "Configures the wait duration which specifies how long the CircuitBreaker should stay open, before it switches to half open. The default is 60 seconds.", + "default" : "60000" }, "writableStackTraceEnabled" : { "type" : "boolean", 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 fc9d044904284..61a26525fb4f7 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 @@ -3928,6 +3928,7 @@ "type" : "boolean", "title" : "Fallback Via Network", "description" : "Whether the fallback goes over the network. If so, the fallback is executed on a separate thread-pool to avoid exhausting the main thread-pool.", + "deprecated" : true, "default" : false }, "id" : { @@ -5508,6 +5509,12 @@ "description" : "Whether bulkhead is enabled or not on the circuit breaker.", "default" : false }, + "bulkheadFairCallHandlingEnabled" : { + "type" : "boolean", + "title" : "Bulkhead Fair Call Handling Enabled", + "description" : "Configures whether the bulkhead uses a fair calling strategy. When enabled (default), a fair strategy guarantees the order of incoming requests (FIFO). When disabled, no ordering is guaranteed and may improve throughput.", + "default" : true + }, "bulkheadMaxConcurrentCalls" : { "type" : "number", "title" : "Bulkhead Max Concurrent Calls", @@ -5515,10 +5522,10 @@ "default" : 25 }, "bulkheadMaxWaitDuration" : { - "type" : "number", + "type" : "string", "title" : "Bulkhead Max Wait Duration", - "description" : "Configures a maximum amount of time which the calling thread will wait to enter the bulkhead.", - "default" : 0 + "description" : "Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. The default is 0 (no waiting).", + "default" : "0" }, "circuitBreaker" : { "type" : "string", @@ -5549,10 +5556,16 @@ "type" : "string" } }, + "maxWaitDurationInHalfOpenState" : { + "type" : "string", + "title" : "Max Wait Duration In Half Open State", + "description" : "Configures the maximum wait duration which controls how long the CircuitBreaker should stay in Half Open state, before it switches to open. Value 0 means circuit breaker will wait in half open state until all permitted calls have been completed.", + "default" : "0" + }, "micrometerEnabled" : { "type" : "boolean", "title" : "Micrometer Enabled", - "description" : "Whether to enable collecting statistics using Micrometer. This requires adding camel-resilience4j-micrometer JAR to the classpath.", + "description" : "Whether to enable collecting statistics using Micrometer for all circuit breaker instances. This is a global setting (configure via camel.resilience4j.micrometerEnabled=true) and requires adding camel-resilience4j-micrometer JAR to the classpath.", "default" : false }, "minimumNumberOfCalls" : { @@ -5581,6 +5594,13 @@ "description" : "Configures the size 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.", "default" : 100 }, + "slidingWindowSynchronizationStrategy" : { + "type" : "string", + "title" : "Sliding Window Synchronization Strategy", + "description" : "Configures the synchronization strategy for the sliding window. LOCK_FREE uses a CAS-based lock-free algorithm for better performance under high concurrency. SYNCHRONIZED uses blocking locks with lower memory allocation.", + "default" : "SYNCHRONIZED", + "enum" : [ "LOCK_FREE", "SYNCHRONIZED" ] + }, "slidingWindowType" : { "type" : "string", "title" : "Sliding Window Type", @@ -5589,10 +5609,10 @@ "enum" : [ "TIME_BASED", "COUNT_BASED" ] }, "slowCallDurationThreshold" : { - "type" : "number", + "type" : "string", "title" : "Slow Call Duration Threshold", - "description" : "Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls percentage.", - "default" : 60 + "description" : "Configures the duration threshold above which calls are considered as slow and increase the slow calls percentage. The default is 60 seconds.", + "default" : "60000" }, "slowCallRateThreshold" : { "type" : "number", @@ -5613,10 +5633,10 @@ "default" : true }, "timeoutDuration" : { - "type" : "number", + "type" : "string", "title" : "Timeout Duration", "description" : "Configures the thread execution timeout. Default value is 1 second.", - "default" : 1000 + "default" : "1000" }, "timeoutEnabled" : { "type" : "boolean", @@ -5630,10 +5650,10 @@ "description" : "References to a custom thread pool to use when timeout is enabled (uses ForkJoinPool.commonPool() by default)." }, "waitDurationInOpenState" : { - "type" : "number", + "type" : "string", "title" : "Wait Duration In Open State", - "description" : "Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it switches to half open.", - "default" : 60 + "description" : "Configures the wait duration which specifies how long the CircuitBreaker should stay open, before it switches to half open. The default is 60 seconds.", + "default" : "60000" }, "writableStackTraceEnabled" : { "type" : "boolean", diff --git a/parent/pom.xml b/parent/pom.xml index 8db8ed52b3e4a..69ab7ea297da5 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -512,7 +512,6 @@ 2.3.26.Final 2.4.2.Final 2.10.2 - 1.0.0 3.1 2.4.1 4.5.28