Skip to main content
Infinitic provides flexible retry mechanisms to handle transient failures automatically. You can configure retry policies using annotations or programmatic configuration.

The @Retry Annotation

The @Retry annotation allows you to define custom retry policies for your tasks and workflows:
import io.infinitic.annotations.Retry

@Retry(with = CustomRetryPolicy::class)
class MyService : MyServiceInterface {
    override fun process(data: String): Result {
        // Task implementation
    }
}

Method-Level Retry

You can also apply retry policies to individual methods:
class MyService : MyServiceInterface {
    
    @Retry(with = AggressiveRetryPolicy::class)
    override fun criticalOperation(): Result {
        // This method has a custom retry policy
    }
    
    override fun normalOperation(): Result {
        // This uses the class-level or default retry policy
    }
}

Implementing WithRetry

Create custom retry policies by implementing the WithRetry interface:
import io.infinitic.tasks.WithRetry

class CustomRetryPolicy : WithRetry {
    override fun getSecondsBeforeRetry(retry: Int, e: Exception): Double? {
        // Return delay in seconds before next retry
        // Return null to stop retrying
        
        return when {
            retry > 5 -> null // Stop after 5 retries
            e is TransientException -> 2.0.pow(retry) // Exponential backoff
            else -> null // Don't retry other exceptions
        }
    }
}

WithRetry Interface

The WithRetry interface has a single method:
fun interface WithRetry {
    fun getSecondsBeforeRetry(retry: Int, e: Exception): Double?
}
Parameters:
  • retry - The retry attempt number (0-indexed)
  • e - The exception that caused the failure
Return value:
  • Double - Delay in seconds before the next retry attempt
  • null - Stop retrying and fail the task

Common Retry Patterns

Exponential Backoff

class ExponentialBackoff : WithRetry {
    override fun getSecondsBeforeRetry(retry: Int, e: Exception): Double? {
        return if (retry < 10) {
            2.0.pow(retry) // 1s, 2s, 4s, 8s, 16s, ...
        } else {
            null // Stop after 10 attempts
        }
    }
}

Fixed Delay

class FixedDelayRetry : WithRetry {
    override fun getSecondsBeforeRetry(retry: Int, e: Exception): Double? {
        return if (retry < 3) {
            5.0 // Wait 5 seconds between attempts
        } else {
            null
        }
    }
}

Exception-Based Retry

class SmartRetry : WithRetry {
    override fun getSecondsBeforeRetry(retry: Int, e: Exception): Double? {
        return when (e) {
            is NetworkException -> {
                // Retry network errors with exponential backoff
                if (retry < 5) 2.0.pow(retry) else null
            }
            is RateLimitException -> {
                // Retry rate limits with longer delay
                if (retry < 3) 60.0 else null
            }
            else -> null // Don't retry other exceptions
        }
    }
}

Immediate Retry with Limit

class ImmediateRetry : WithRetry {
    override fun getSecondsBeforeRetry(retry: Int, e: Exception): Double? {
        return if (retry < 3) 0.0 else null // Retry immediately, up to 3 times
    }
}

Workflow Task Retry

You can manually retry a workflow’s task execution using the client:
val workflow = client.getWorkflowById(MyWorkflow::class.java, workflowId)
workflow.retryAsync()
This is useful when you want to retry the workflow’s internal task after fixing an issue.

Retry Events

Infinitic emits CloudEvents for retry operations:
  • retryScheduled - A retry has been scheduled for a failed task
  • retryTask - Retrying a specific task
  • retryExecutor - Retrying workflow executor

WithRetryBuilder

For more complex scenarios, you can use WithRetryBuilder to create retry policies dynamically:
fun interface WithRetryBuilder {
    fun build(): WithRetry
}

Best Practices

Exponential backoff prevents overwhelming systems during outages and gives them time to recover.
Always set a maximum number of retries to prevent infinite retry loops.
Retry transient errors (network, timeout) but not permanent errors (validation, not found).
Add random variation to retry delays to prevent many tasks from retrying simultaneously.
Track retry rates to identify problematic services or workflows.

Build docs developers (and LLMs) love