Kora aop resilient
Skill kora-projects/kora-skills/plugins/kora-v1/skills/kora-aop-resilient
Kora resilience aspects — @CircuitBreaker, @Retry, @Timeout, @Fallback from the resilient-kora module (ResilientModule). Covers circuit breaker states (CLOSED/OPEN/HALF_OPEN), retry backoff, execution timeouts, fallback methods, custom CircuitBreakerPredicate/RetryPredicate/FallbackPredicate, the imperative *Manager API, and stacking aspects on one method. Use when adding fault tolerance to outbound HTTP/gRPC calls, database or external-service operations, debugging "circuit never opens", TimeoutExhaustedException, or fallback not firing, or wiring resilient.* config keys (failureRateThreshold, minimumRequiredCalls, attempts, delayStep, waitDurationInOpenState).From its SKILL.md
npx -y skills add kora-projects/kora-skills --skill kora-aop-resilientAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
- runs commandsInstructs the agent to run 2 commands, including `find build -name "*__AopProxy.java" | head -5` and 1 more.
SKILL.md
8.2 KB, ~1.9k tokens by cl100k_base, as published. Nobody here has run it
Kora AOP Resilient
Compile-time AOP annotations for fault tolerance: @Retry, @CircuitBreaker, @Timeout, @Fallback. They are generated into $<Class>__AopProxy classes at build time — no reflection. Provided by the resilient-kora module via ResilientModule.
Quick Navigation:
- Quick Start — get running in four steps
- Combined Pattern — stack all annotations on one method
- References — per-aspect deep dives
Quick Start
1. Add the dependency and annotation processor
dependencies {
// All Kora artifacts inherit their version from the kora-parent BOM — never pin them individually.
annotationProcessor "ru.tinkoff.kora:annotation-processors" // mandatory: generates the AOP proxies
implementation "ru.tinkoff.kora:resilient-kora"
}
Kotlin uses
ksp "ru.tinkoff.kora:symbol-processors"instead ofannotationProcessor.
2. Enable ResilientModule
@KoraApp
public interface Application extends
HoconConfigModule,
LogbackModule,
ResilientModule { } // enables the resilience aspects
3. Apply Resilience Annotations
Each annotation lives in its own package:
| Annotation | Import |
|---|---|
@CircuitBreaker | ru.tinkoff.kora.resilient.circuitbreaker.annotation.CircuitBreaker |
@Retry | ru.tinkoff.kora.resilient.retry.annotation.Retry |
@Timeout | ru.tinkoff.kora.resilient.timeout.annotation.Timeout |
@Fallback | ru.tinkoff.kora.resilient.fallback.annotation.Fallback |
@Component
public class PaymentService { // MUST be non-final (Java) / open (Kotlin) for aspects to apply
@Fallback(value = "payment.process", method = "processFallback(request)")
@CircuitBreaker("payment.process")
@Retry("payment.process")
@Timeout("payment.process")
public PaymentResult process(PaymentRequest request) {
return paymentGateway.charge(request);
}
protected PaymentResult processFallback(PaymentRequest request) {
return PaymentResult.pendingManualReview();
}
}
The annotation value is a config key, not a shared identifier — @Retry("payment.process") reads resilient.retry."payment.process". Different aspects on the same method may use independent keys.
4. Configure Resilience
resilient {
timeout {
default { duration = "1s" }
"payment.process" { duration = "5s" }
}
retry {
default {
delay = "100ms"
attempts = 3
delayStep = "100ms"
}
}
circuitbreaker {
default {
slidingWindowSize = 100
minimumRequiredCalls = 10
failureRateThreshold = 50
waitDurationInOpenState = "30s"
permittedCallsInHalfOpenState = 5
}
}
fallback {
default { enabled = true }
}
}
Important: Use
minimumRequiredCalls(NOTminimumNumberOfCalls) — Kora-specific key.
Combined Resilience Pattern
Recommended order (outer → inner):
@Component
public class PaymentClient {
// Order (outer → inner):
// 1. @Fallback — degraded response if everything fails
// 2. @CircuitBreaker — fail fast if repeatedly failing
// 3. @Retry — retry transient failures
// 4. @Timeout — bound each attempt
@Fallback(value = "payment.charge", method = "chargeFallback(request)")
@CircuitBreaker("payment.charge")
@Retry("payment.charge")
@Timeout("payment.charge")
public PaymentResult charge(PaymentRequest request) {
return httpClient.post("/payments", request);
}
protected PaymentResult chargeFallback(PaymentRequest request) {
return PaymentResult.pendingManualReview();
}
}
Execution flow:
@Timeoutbounds the actual HTTP call@Retryrepeats on transient failures (up to N attempts)@CircuitBreakeropens if failures exceed threshold@Fallbackreturns degraded response if circuit is open or all retries fail
References
Detailed guides with configuration options, patterns, and examples:
| Reference | Description |
|---|---|
| retry-reference.md | @Retry, predicates, backoff patterns, wait time calculation |
| circuit-breaker-reference.md | @CircuitBreaker, state machine (CLOSED/OPEN/HALF_OPEN), custom predicates |
| timeout-reference.md | @Timeout patterns, per-attempt vs overall timeout, thread interruption |
| fallback-reference.md | @Fallback methods, signature rules, fallback patterns |
| resilience-config-reference.md | Full configuration reference, custom predicates, high-throughput tuning |
Supported Signatures
Java
Class must be non-final for AOP to work.
| Return Type | Example |
|---|---|
T (or Void) | User getUser(String id) |
Optional<T> | Optional<User> getUser(String id) |
Mono<T> / Flux<T> | Project Reactor types (require io.projectreactor:reactor-core) |
Kotlin
Class and methods must be open for AOP to work.
| Return Type | Example |
|---|---|
T / T? / Unit | fun getUser(id: String): User? |
suspend fun ... : T | suspend fun getUserAsync(id: String): User (requires kotlinx-coroutines-core) |
Flow<T> | fun getAllUsers(): Flow<User> (requires kotlinx-coroutines-core) |
Common Pitfalls
| Problem | Solution |
|---|---|
| Annotations don't trigger | Java: class must be non-final. Kotlin: class and methods must be open |
| Circuit breaker never opens | Check minimumRequiredCalls — need enough calls to evaluate |
| Circuit breaker reacts to 404 | Implement CircuitBreakerPredicate to exclude business errors |
| Fallback not called | Check method signature: return type compatible, parameters match subset |
| Retry makes latency worse | Estimate worst-case: attempts × (delay + delayStep). Reduce for latency-sensitive paths |
| Config not applied | Config key must match annotation value: @Retry("custom") → resilient.retry."custom" |
Troubleshooting
Verify AOP is working
# Check generated proxy classes
find build -name "*__AopProxy.java" | head -5
If no proxies are generated:
- Check the class is non-final (Java) /
open(Kotlin), and the method isopenin Kotlin. - Verify the annotation processor is wired: Java
annotationProcessor "ru.tinkoff.kora:annotation-processors", Kotlinksp "ru.tinkoff.kora:symbol-processors". - Clean rebuild:
./gradlew clean build --no-daemon
Enable debug logging
logging.levels {
"ru.tinkoff.kora.resilient": "DEBUG"
}
Assets
Templates in assets/:
| Template | Description |
|---|---|
ResilientService.java.template | Full resilience stack (Java) |
ResilientService.kt.template | Full resilience stack (Kotlin) |
RetryService.*.template | @Retry pattern |
CircuitBreakerService.*.template | @CircuitBreaker pattern |
TimeoutService.*.template | @Timeout pattern |
FallbackService.*.template | @Fallback pattern |
See assets/README.md for usage.
See Also
- kora-http-client — Pair resilient with outbound HTTP clients
- kora-telemetry-metrics — Monitor retry attempts, circuit breaker state
- kora-aop-logging — Add logging to resilient services
What ships with it: 16 files
54.3 KB alongside SKILL.md
assets/
- CircuitBreakerService.java.template2.0 KB
- CircuitBreakerService.kt.template1.6 KB
- FallbackService.java.template2.5 KB
- FallbackService.kt.template2.1 KB
- ResilientService.java.template2.2 KB
- ResilientService.kt.template2.6 KB
- RetryService.java.template1.8 KB
- RetryService.kt.template1.5 KB
- TimeoutService.java.template1.7 KB
- TimeoutService.kt.template1.5 KB
evals/
- evals.json6.5 KB
references/
- circuit-breaker-reference.md5.1 KB
- fallback-reference.md6.5 KB
- resilience-config-reference.md8.5 KB
- retry-reference.md3.6 KB
- timeout-reference.md4.5 KB