Skip to main content

nexora-retry

Retry policies for capability executions. The RetryInterceptor consults the policy registry before each re-attempt.

RetryPolicy interface

public interface RetryPolicy {
boolean shouldRetry(int attemptsMade, Throwable cause);
Duration backoffDelay(int attemptsMade);
}

Two built-in implementations:

ClassBehaviour
NoRetryPolicyNever retries. Default when no policy is configured.
ExponentialBackoffPolicyExponential delay with ±25% jitter.

ExponentialBackoffPolicy

RetryPolicy policy = ExponentialBackoffPolicy.builder()
.maxAttempts(4)
.initialDelay(Duration.ofMillis(100))
.multiplier(2.0)
.maxDelay(Duration.ofSeconds(8))
.retryOn(IOException.class, TimeoutException.class)
.build();
ParameterDefaultDescription
maxAttempts3Total attempts including the first call
initialDelay200 msDelay before attempt 2
multiplier2.0Multiplied each retry (must be > 1.0)
maxDelay10 sUpper bound on delay between retries
retryOnall exceptionsRestrict retries to specific exception types

The ±25% jitter prevents retry storms when many concurrent executions fail simultaneously.


RetryPolicyRegistry

Maps named policy IDs to RetryPolicy instances. Referenced by StepDefinition.retryPolicyId.

NexoraEngine engine = NexoraEngine.builder()
.withDefaultRetryPolicy(
ExponentialBackoffPolicy.builder()
.maxAttempts(3)
.initialDelay(Duration.ofMillis(200))
.build()
)
.build();

The default retry policy applies to any step that does not declare a retryPolicyId. To disable retries globally, pass RetryPolicy.noRetry().


Per-step retry policies

Override retry behaviour on a per-step basis via StepDefinition:

new StepDefinition(
"charge",
"charge_card",
goal -> goal.contains("order"),
inputs,
"chargeResult",
Set.of("validate"),
"payment-retry-policy", // matches a named policy in the registry
Duration.ofSeconds(5) // per-step timeout
)