Add resilience: Spring Framework 7 @Retryable and @ConcurrencyLimit
Companion code for "Spring Framework 7's Built-in Resilience: @Retryable, @ConcurrencyLimit, and What's Left for Resilience4j". Every retry counted by recording real invocations: defaults, backoff and jitter, timeout, reactive and CompletableFuture returns, the concurrency limit's BLOCK and REJECT policies, retries around transactions, composition with Resilience4j 2.4.0, and the annotation API across 7.0.0-7.0.9. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01C3TETMrqVUWeFkNtz3Jbo3
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
# Public API of the resilience support, per Spring Framework release
|
||||
|
||||
## 7.0.0
|
||||
@Retryable [delay, delayString, excludes, includes, jitter, jitterString, maxDelay, maxDelayString, maxRetries, maxRetriesString, multiplier, multiplierString, predicate, timeUnit, value]
|
||||
@ConcurrencyLimit [limit, limitString, value]
|
||||
RetryPolicy.Builder [backOff, build, delay, excludes, includes, jitter, maxDelay, maxRetries, multiplier, predicate]
|
||||
RetryListener [beforeRetry, onRetryFailure, onRetryPolicyExhaustion, onRetryPolicyInterruption, onRetrySuccess]
|
||||
|
||||
## 7.0.1
|
||||
@Retryable [delay, delayString, excludes, includes, jitter, jitterString, maxDelay, maxDelayString, maxRetries, maxRetriesString, multiplier, multiplierString, predicate, timeUnit, value]
|
||||
@ConcurrencyLimit [limit, limitString, value]
|
||||
RetryPolicy.Builder [backOff, build, delay, excludes, includes, jitter, maxDelay, maxRetries, multiplier, predicate]
|
||||
RetryListener [beforeRetry, onRetryFailure, onRetryPolicyExhaustion, onRetryPolicyInterruption, onRetrySuccess]
|
||||
|
||||
## 7.0.2
|
||||
@Retryable [delay, delayString, excludes, includes, jitter, jitterString, maxDelay, maxDelayString, maxRetries, maxRetriesString, multiplier, multiplierString, predicate, timeUnit, timeout, timeoutString, value]
|
||||
@ConcurrencyLimit [limit, limitString, value]
|
||||
RetryPolicy.Builder [backOff, build, delay, excludes, includes, jitter, maxDelay, maxRetries, multiplier, predicate, timeout]
|
||||
RetryListener [beforeRetry, onRetryFailure, onRetryPolicyExhaustion, onRetryPolicyInterruption, onRetryPolicyTimeout, onRetrySuccess, onRetryableExecution]
|
||||
|
||||
## 7.0.3
|
||||
@Retryable [delay, delayString, excludes, includes, jitter, jitterString, maxDelay, maxDelayString, maxRetries, maxRetriesString, multiplier, multiplierString, predicate, timeUnit, timeout, timeoutString, value]
|
||||
@ConcurrencyLimit [limit, limitString, policy, value]
|
||||
RetryPolicy.Builder [backOff, build, delay, excludes, includes, jitter, maxDelay, maxRetries, multiplier, predicate, timeout]
|
||||
RetryListener [beforeRetry, onRetryFailure, onRetryPolicyExhaustion, onRetryPolicyInterruption, onRetryPolicyTimeout, onRetrySuccess, onRetryableExecution]
|
||||
|
||||
## 7.0.9
|
||||
@Retryable [delay, delayString, excludes, includes, jitter, jitterString, maxDelay, maxDelayString, maxRetries, maxRetriesString, multiplier, multiplierString, predicate, timeUnit, timeout, timeoutString, value]
|
||||
@ConcurrencyLimit [limit, limitString, policy, value]
|
||||
RetryPolicy.Builder [backOff, build, delay, excludes, includes, jitter, maxDelay, maxRetries, multiplier, predicate, timeout]
|
||||
RetryListener [beforeRetry, onRetryFailure, onRetryPolicyExhaustion, onRetryPolicyInterruption, onRetryPolicyTimeout, onRetrySuccess, onRetryableExecution]
|
||||
@@ -0,0 +1,10 @@
|
||||
# GET /demo/limit/block (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"callers": 10,
|
||||
"succeeded": 10,
|
||||
"failed": {},
|
||||
"max concurrently inside the method": 2,
|
||||
"elapsed (ms)": 1006
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
# GET /demo/limit/limit-and-retry (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"callers": 2,
|
||||
"succeeded": 2,
|
||||
"failed": {},
|
||||
"max concurrently inside the method": 1,
|
||||
"elapsed (ms)": 815
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
# GET /demo/limit/none (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"callers": 10,
|
||||
"succeeded": 10,
|
||||
"failed": {},
|
||||
"max concurrently inside the method": 10,
|
||||
"elapsed (ms)": 203
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# GET /demo/limit/r4j-bulkhead (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"callers": 10,
|
||||
"succeeded": 2,
|
||||
"failed": {
|
||||
"io.github.resilience4j.bulkhead.BulkheadFullException": 8
|
||||
},
|
||||
"max concurrently inside the method": 2,
|
||||
"elapsed (ms)": 231
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# GET /demo/limit/reject (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"callers": 10,
|
||||
"succeeded": 2,
|
||||
"failed": {
|
||||
"org.springframework.resilience.InvocationRejectedException": 8
|
||||
},
|
||||
"max concurrently inside the method": 2,
|
||||
"elapsed (ms)": 205
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
# Spring retry has no metrics of its own; the only meter is the one RetryEvents registers.
|
||||
$ curl /actuator/metrics | grep -iE 'retry|resilience4j'
|
||||
app.retry.failures
|
||||
resilience4j.bulkhead.available.concurrent.calls
|
||||
resilience4j.bulkhead.max.allowed.concurrent.calls
|
||||
resilience4j.circuitbreaker.buffered.calls
|
||||
resilience4j.circuitbreaker.calls
|
||||
resilience4j.circuitbreaker.failure.rate
|
||||
resilience4j.circuitbreaker.not.permitted.calls
|
||||
resilience4j.circuitbreaker.slow.call.rate
|
||||
resilience4j.circuitbreaker.slow.calls
|
||||
resilience4j.circuitbreaker.state
|
||||
resilience4j.retry.calls
|
||||
resilience4j.timelimiter.calls
|
||||
@@ -0,0 +1,7 @@
|
||||
# GET /demo/proxy/gateway (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
[
|
||||
"proxy type: CGLIB",
|
||||
"org.springframework.resilience.annotation.RetryAnnotationBeanPostProcessor$RetryAnnotationInterceptor order=2147483647"
|
||||
]
|
||||
@@ -0,0 +1,12 @@
|
||||
# GET /demo/proxy/payments (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
[
|
||||
"proxy type: CGLIB",
|
||||
"org.springframework.resilience.annotation.RetryAnnotationBeanPostProcessor$RetryAnnotationInterceptor order=2147483647",
|
||||
"org.springframework.aop.interceptor.ExposeInvocationInterceptor order=-2147483647",
|
||||
"org.springframework.aop.aspectj.AspectJAroundAdvice order=2147483642",
|
||||
"org.springframework.aop.aspectj.AspectJAroundAdvice order=2147483643",
|
||||
"org.springframework.aop.aspectj.AspectJAroundAdvice order=2147483645",
|
||||
"org.springframework.aop.aspectj.AspectJAroundAdvice order=2147483646"
|
||||
]
|
||||
@@ -0,0 +1,8 @@
|
||||
# GET /demo/proxy/reports (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
[
|
||||
"proxy type: CGLIB",
|
||||
"org.springframework.resilience.annotation.ConcurrencyLimitBeanPostProcessor$ConcurrencyLimitInterceptor order=2147483647",
|
||||
"org.springframework.resilience.annotation.RetryAnnotationBeanPostProcessor$RetryAnnotationInterceptor order=2147483647"
|
||||
]
|
||||
@@ -0,0 +1,8 @@
|
||||
# GET /demo/proxy/stock-writer (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
[
|
||||
"proxy type: CGLIB",
|
||||
"org.springframework.resilience.annotation.RetryAnnotationBeanPostProcessor$RetryAnnotationInterceptor order=2147483647",
|
||||
"org.springframework.transaction.interceptor.TransactionInterceptor order=2147483647"
|
||||
]
|
||||
@@ -0,0 +1,22 @@
|
||||
# GET /demo/r4j/breaker (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"calls made": 11,
|
||||
"calls that reached the downstream": 8,
|
||||
"of which before the breaker opened": 5,
|
||||
"outcomes": [
|
||||
"1: TransientException: payment gateway 503 (call 1) [state after: CLOSED]",
|
||||
"2: TransientException: payment gateway 503 (call 2) [state after: CLOSED]",
|
||||
"3: TransientException: payment gateway 503 (call 3) [state after: CLOSED]",
|
||||
"4: TransientException: payment gateway 503 (call 4) [state after: CLOSED]",
|
||||
"5: TransientException: payment gateway 503 (call 5) [state after: OPEN]",
|
||||
"6: CallNotPermittedException: CircuitBreaker 'payments' is OPEN and does not permit further calls [state after: OPEN]",
|
||||
"7: CallNotPermittedException: CircuitBreaker 'payments' is OPEN and does not permit further calls [state after: OPEN]",
|
||||
"8: CallNotPermittedException: CircuitBreaker 'payments' is OPEN and does not permit further calls [state after: OPEN]",
|
||||
"-- 2.1 s later, downstream recovered --",
|
||||
"9: returned charged [state after: HALF_OPEN]",
|
||||
"10: returned charged [state after: CLOSED]",
|
||||
"11: returned charged [state after: CLOSED]"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
# GET /demo/r4j/combo (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"call 1": {
|
||||
"caller got": "TransientException: payment gateway 503 (call 4)",
|
||||
"method body ran": 4,
|
||||
"elapsed (ms)": 35,
|
||||
"breaker: buffered / failed / not permitted": "4 / 4 / 0",
|
||||
"breaker state": "CLOSED"
|
||||
},
|
||||
"call 2": {
|
||||
"caller got": "CallNotPermittedException: CircuitBreaker 'combo' is OPEN and does not permit further calls",
|
||||
"method body ran": 1,
|
||||
"elapsed (ms)": 33,
|
||||
"breaker: buffered / failed / not permitted": "5 / 5 / 3",
|
||||
"breaker state": "OPEN"
|
||||
},
|
||||
"MethodRetryEvents": [
|
||||
"chargeWithBoth failed with TransientException -> will retry",
|
||||
"chargeWithBoth failed with TransientException -> will retry",
|
||||
"chargeWithBoth failed with TransientException -> will retry",
|
||||
"chargeWithBoth failed with TransientException -> will retry",
|
||||
"chargeWithBoth failed with RetryException -> retry aborted",
|
||||
"chargeWithBoth failed with TransientException -> will retry",
|
||||
"chargeWithBoth failed with CallNotPermittedException -> will retry",
|
||||
"chargeWithBoth failed with CallNotPermittedException -> will retry",
|
||||
"chargeWithBoth failed with CallNotPermittedException -> will retry",
|
||||
"chargeWithBoth failed with RetryException -> retry aborted"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
# GET /demo/r4j/retry (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"invocations": 3,
|
||||
"started at (ms)": [
|
||||
7,
|
||||
26,
|
||||
36
|
||||
],
|
||||
"gaps (ms)": [
|
||||
19,
|
||||
10
|
||||
],
|
||||
"elapsed (ms)": 37,
|
||||
"caller": "threw: com.ankurm.resilience.support.TransientException: payment gateway 503 (call 3)"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# GET /demo/r4j/timelimiter (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"invocations": 1,
|
||||
"started at (ms)": [
|
||||
11
|
||||
],
|
||||
"gaps (ms)": [],
|
||||
"elapsed (ms)": 512,
|
||||
"caller": "threw: java.util.concurrent.TimeoutException: TimeLimiter 'slow' recorded a timeout exception."
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# GET /demo/retry/cause (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"invocations": 3,
|
||||
"started at (ms)": [
|
||||
1,
|
||||
11,
|
||||
23
|
||||
],
|
||||
"gaps (ms)": [
|
||||
10,
|
||||
12
|
||||
],
|
||||
"elapsed (ms)": 26,
|
||||
"caller": "threw: java.io.UncheckedIOException: java.io.IOException: socket reset on attempt 3",
|
||||
"MethodRetryEvents": [
|
||||
"wrappedCause failed with UncheckedIOException -> will retry",
|
||||
"wrappedCause failed with UncheckedIOException -> will retry",
|
||||
"wrappedCause failed with UncheckedIOException -> will retry",
|
||||
"wrappedCause failed with RetryException -> retry aborted"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
# GET /demo/retry/defaults (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"invocations": 3,
|
||||
"started at (ms)": [
|
||||
27,
|
||||
1036,
|
||||
2037
|
||||
],
|
||||
"gaps (ms)": [
|
||||
1009,
|
||||
1001
|
||||
],
|
||||
"elapsed (ms)": 2037,
|
||||
"caller": "returned: ok after 3 invocation(s)",
|
||||
"MethodRetryEvents": [
|
||||
"defaults failed with TransientException -> will retry",
|
||||
"defaults failed with TransientException -> will retry"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
# The same @Retryable method with @EnableResilientMethods switched off (demo.resilience.enabled=false)
|
||||
|
||||
{
|
||||
"invocations": 1,
|
||||
"started at (ms)": [
|
||||
0
|
||||
],
|
||||
"gaps (ms)": [],
|
||||
"elapsed (ms)": 0,
|
||||
"caller": "threw: com.ankurm.resilience.support.TransientException: attempt 1 failed"
|
||||
}
|
||||
|
||||
# Startup log lines mentioning retry or resilience:
|
||||
(none)
|
||||
@@ -0,0 +1,26 @@
|
||||
# GET /demo/retry/exhausted (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"invocations": 4,
|
||||
"started at (ms)": [
|
||||
0,
|
||||
1001,
|
||||
2002,
|
||||
3004
|
||||
],
|
||||
"gaps (ms)": [
|
||||
1001,
|
||||
1001,
|
||||
1002
|
||||
],
|
||||
"elapsed (ms)": 3008,
|
||||
"caller": "threw: com.ankurm.resilience.support.TransientException: attempt 4 failed",
|
||||
"MethodRetryEvents": [
|
||||
"defaults failed with TransientException -> will retry",
|
||||
"defaults failed with TransientException -> will retry",
|
||||
"defaults failed with TransientException -> will retry",
|
||||
"defaults failed with TransientException -> will retry",
|
||||
"defaults failed with RetryException -> retry aborted"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
# GET /demo/retry/exponential (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"invocations": 6,
|
||||
"started at (ms)": [
|
||||
3,
|
||||
104,
|
||||
304,
|
||||
705,
|
||||
1206,
|
||||
1707
|
||||
],
|
||||
"gaps (ms)": [
|
||||
101,
|
||||
200,
|
||||
401,
|
||||
501,
|
||||
501
|
||||
],
|
||||
"elapsed (ms)": 1707,
|
||||
"caller": "threw: com.ankurm.resilience.support.TransientException: attempt 6 failed",
|
||||
"MethodRetryEvents": [
|
||||
"exponential failed with TransientException -> will retry",
|
||||
"exponential failed with TransientException -> will retry",
|
||||
"exponential failed with TransientException -> will retry",
|
||||
"exponential failed with TransientException -> will retry",
|
||||
"exponential failed with TransientException -> will retry",
|
||||
"exponential failed with TransientException -> will retry",
|
||||
"exponential failed with RetryException -> retry aborted"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# GET /demo/retry/future (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"invocations": 1,
|
||||
"started at (ms)": [
|
||||
0
|
||||
],
|
||||
"gaps (ms)": [],
|
||||
"elapsed (ms)": 1,
|
||||
"caller": "threw: com.ankurm.resilience.support.TransientException: attempt 1 failed"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
# GET /demo/retry/hang (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"invocations": 1,
|
||||
"started at (ms)": [
|
||||
1
|
||||
],
|
||||
"gaps (ms)": [],
|
||||
"elapsed (ms)": 1502,
|
||||
"caller": "threw: com.ankurm.resilience.support.TransientException: slow failure",
|
||||
"MethodRetryEvents": [
|
||||
"hangingWithTimeout failed with TransientException -> will retry",
|
||||
"hangingWithTimeout failed with RetryException -> retry aborted"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
# GET /demo/retry/includes (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"invocations": 1,
|
||||
"started at (ms)": [
|
||||
1
|
||||
],
|
||||
"gaps (ms)": [],
|
||||
"elapsed (ms)": 0,
|
||||
"caller": "threw: java.lang.IllegalArgumentException: not in includes",
|
||||
"MethodRetryEvents": [
|
||||
"onlyIllegalState failed with IllegalArgumentException -> will retry",
|
||||
"onlyIllegalState failed with RetryException -> retry aborted"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
# GET /demo/retry/jitter (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"invocations": 7,
|
||||
"started at (ms)": [
|
||||
0,
|
||||
254,
|
||||
465,
|
||||
761,
|
||||
1055,
|
||||
1328,
|
||||
1621
|
||||
],
|
||||
"gaps (ms)": [
|
||||
254,
|
||||
211,
|
||||
296,
|
||||
294,
|
||||
273,
|
||||
293
|
||||
],
|
||||
"elapsed (ms)": 1622,
|
||||
"caller": "threw: com.ankurm.resilience.support.TransientException: attempt 7 failed",
|
||||
"MethodRetryEvents": [
|
||||
"jittered failed with TransientException -> will retry",
|
||||
"jittered failed with TransientException -> will retry",
|
||||
"jittered failed with TransientException -> will retry",
|
||||
"jittered failed with TransientException -> will retry",
|
||||
"jittered failed with TransientException -> will retry",
|
||||
"jittered failed with TransientException -> will retry",
|
||||
"jittered failed with TransientException -> will retry",
|
||||
"jittered failed with RetryException -> retry aborted"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
# GET /demo/retry/mono (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"invocations": 3,
|
||||
"started at (ms)": [
|
||||
37,
|
||||
65,
|
||||
75
|
||||
],
|
||||
"gaps (ms)": [
|
||||
28,
|
||||
10
|
||||
],
|
||||
"elapsed (ms)": 75,
|
||||
"caller": "returned: ok after 3 invocation(s)",
|
||||
"MethodRetryEvents": [
|
||||
"mono failed with TransientException -> will retry",
|
||||
"mono failed with TransientException -> will retry"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# GET /demo/retry/self-invocation (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"invocations": 1,
|
||||
"started at (ms)": [
|
||||
0
|
||||
],
|
||||
"gaps (ms)": [],
|
||||
"elapsed (ms)": 0,
|
||||
"caller": "threw: com.ankurm.resilience.support.TransientException: attempt 1 failed"
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# GET /demo/retry/timeout (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"invocations": 3,
|
||||
"started at (ms)": [
|
||||
303,
|
||||
705,
|
||||
1106
|
||||
],
|
||||
"gaps (ms)": [
|
||||
402,
|
||||
401
|
||||
],
|
||||
"elapsed (ms)": 1105,
|
||||
"caller": "threw: com.ankurm.resilience.support.TransientException: attempt 3 failed",
|
||||
"MethodRetryEvents": [
|
||||
"slowWithTimeout failed with TransientException -> will retry",
|
||||
"slowWithTimeout failed with TransientException -> will retry",
|
||||
"slowWithTimeout failed with TransientException -> will retry",
|
||||
"slowWithTimeout failed with RetryException -> retry aborted"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# GET /demo/tx/joined (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"caller got": "org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only",
|
||||
"attempts": [
|
||||
"attempt 1: transaction active=true, connection holder @6135f416",
|
||||
"attempt 2: transaction active=true, connection holder @6135f416",
|
||||
"attempt 3: transaction active=true, connection holder @6135f416"
|
||||
],
|
||||
"rows in stock_movement": 0
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# GET /demo/tx/standalone (Spring Framework 7.0.9, Resilience4j 2.4.0, JDK 25)
|
||||
# Source: src/main/java/com/ankurm/resilience/web/DemoController.java
|
||||
|
||||
{
|
||||
"caller got": "success",
|
||||
"attempts": [
|
||||
"attempt 1: transaction active=true, connection holder @6aa73704",
|
||||
"attempt 2: transaction active=true, connection holder @1978b580",
|
||||
"attempt 3: transaction active=true, connection holder @7d5534c2"
|
||||
],
|
||||
"rows in stock_movement": 1
|
||||
}
|
||||
Reference in New Issue
Block a user