RetryPolicy
Configurable retry policies for each step.
Policy Types
exponential()
Exponential backoff with jitter. Recommended for most cases.
.retry(exponential(3, Duration.ofSeconds(1)))
// Attempts: 1s, 2s, 4s (with jitter)
| Parameter | Type | Description |
|---|---|---|
maxAttempts | int | Maximum number of attempts |
initialDelay | Duration | Initial delay between attempts |
With custom limits
.retry(exponential()
.maxAttempts(5)
.initialDelay(Duration.ofSeconds(1))
.maxDelay(Duration.ofMinutes(5))
.multiplier(2.0)
.jitterFactor(0.1))
fixed()
Fixed delay between attempts.
.retry(fixed(3, Duration.ofSeconds(5)))
// Attempts: 5s, 5s, 5s
| Parameter | Type | Description |
|---|---|---|
maxAttempts | int | Maximum number of attempts |
delay | Duration | Fixed delay between attempts |
infinite()
Infinite retry. Use only for operations that must eventually succeed.
.retry(infinite())
// Attempts: 1min, 2min, 4min, 8min... (up to maxDelay)
With limits
.retry(infinite()
.initialDelay(Duration.ofMinutes(1))
.maxDelay(Duration.ofHours(1)))
Warning
Use infinite() only for idempotent operations such as notifications or cache updates.
none()
No retry. Failure on the first attempt results in compensation.
.retry(none())
// Fails immediately
Comparison
| Policy | Attempts | Delay | Use |
|---|---|---|---|
exponential() | Limited | Growing | External APIs, databases |
fixed() | Limited | Constant | Simple operations |
infinite() | Unlimited | Growing | Notifications, webhooks |
none() | 1 | - | Operations that cannot fail |
Global Configuration
Define a default policy in application.yml:
sagaweaw:
retry:
default-policy: exponential
max-attempts: 3
initial-delay: 1s
max-delay: 30s
multiplier: 2.0
jitter-factor: 0.1
Steps without an explicit .retry() will use the global policy.
Full Example
@Override
public void define(SagaBuilder<PaymentContext> builder) {
builder
// Internal API: fast retry
.step("validate")
.invoke(this::validate)
.retry(exponential(3, Duration.ofMillis(100)))
// External API: slower retry
.step("charge-stripe")
.invoke(this::chargeStripe)
.compensate(this::refundStripe)
.retry(exponential()
.maxAttempts(5)
.initialDelay(Duration.ofSeconds(2))
.maxDelay(Duration.ofSeconds(30)))
// Notification: must always succeed
.step("send-receipt")
.invoke(this::sendReceipt)
.retry(infinite()
.initialDelay(Duration.ofMinutes(1))
.maxDelay(Duration.ofHours(1)))
.build();
}
Kotlin
The sagaweaw-kotlin module provides kotlin.time.Duration support so you don't need Duration.ofSeconds():
// Java
.retryPolicy(RetryPolicy.exponential(3, Duration.ofSeconds(5)))
// Kotlin
retry(exponentialRetry(3, 5.seconds))
retry(fixedRetry(3, 2.seconds))
retry(infiniteRetry(1.minutes))
See the Kotlin guide → for setup.