Files

114 lines
2.8 KiB
Go
Raw Permalink Normal View History

package recovery
import (
"time"
"go.temporal.io/sdk/temporal"
"go.temporal.io/sdk/workflow"
)
// RetryPolicy defines exponential backoff retry behavior
type RetryPolicy struct {
// InitialInterval is the first wait duration
InitialInterval time.Duration
// MaximumInterval is the max wait duration between retries
MaximumInterval time.Duration
// BackoffCoefficient is the multiplier for each retry
BackoffCoefficient float64
// MaximumAttempts is the max number of retries (0 = unlimited)
MaximumAttempts int32
}
// DefaultRetryPolicy returns a sensible default retry policy
func DefaultRetryPolicy() *RetryPolicy {
return &RetryPolicy{
InitialInterval: time.Second,
MaximumInterval: time.Minute,
BackoffCoefficient: 2.0,
MaximumAttempts: 5,
}
}
// ActivityRetryPolicy returns a retry policy for activities
func ActivityRetryPolicy() *RetryPolicy {
return &RetryPolicy{
InitialInterval: 2 * time.Second,
MaximumInterval: 5 * time.Minute,
BackoffCoefficient: 2.0,
MaximumAttempts: 3,
}
}
// LLMActivityRetryPolicy returns a retry policy for LLM activities (more lenient)
func LLMActivityRetryPolicy() *RetryPolicy {
return &RetryPolicy{
InitialInterval: 5 * time.Second,
MaximumInterval: 10 * time.Minute,
BackoffCoefficient: 1.5,
MaximumAttempts: 5,
}
}
// ToTemporalRetryPolicy converts to Temporal SDK's RetryPolicy
func (p *RetryPolicy) ToTemporalRetryPolicy() *temporal.RetryPolicy {
if p == nil {
return nil
}
return &temporal.RetryPolicy{
InitialInterval: p.InitialInterval,
MaximumInterval: p.MaximumInterval,
BackoffCoefficient: p.BackoffCoefficient,
MaximumAttempts: p.MaximumAttempts,
}
}
// ApplyRetryPolicy applies a retry policy to activity options
func ApplyRetryPolicy(opts workflow.ActivityOptions, policy *RetryPolicy) workflow.ActivityOptions {
if policy == nil {
return opts
}
opts.RetryPolicy = policy.ToTemporalRetryPolicy()
return opts
}
// IsRetryableError checks if an error is retryable
func IsRetryableError(err error) bool {
if err == nil {
return false
}
// Temporal SDK errors that should not be retried
if temporal.IsTimeoutError(err) {
return true // Timeouts are usually retryable
}
if temporal.IsCanceledError(err) {
return false // Canceled workflows should not be retried
}
if temporal.IsApplicationError(err) {
// Application errors are retryable by default
return true
}
// Generic errors are retryable
return true
}
// RetryCount holds retry attempt information
type RetryCount struct {
Current int
Maximum int
}
// CanRetry checks if we can retry
func (rc *RetryCount) CanRetry() bool {
if rc.Maximum == 0 {
return true // Unlimited retries
}
return rc.Current < rc.Maximum
}
// Increment increments the retry count
func (rc *RetryCount) Increment() {
rc.Current++
}