> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/temporalio/temporal/llms.txt
> Use this file to discover all available pages before exploring further.

# Retry Policies

> Configure automatic retry behavior for activities and workflows with exponential backoff

## Overview

Temporal automatically retries failed activities and child workflows according to configurable retry policies:

* **Exponential backoff** - Increasing delays between retry attempts
* **Maximum attempts** - Limit total retry count
* **Timeout controls** - Cap retry duration
* **Non-retriable errors** - Fail immediately for specific error types
* **Backoff coefficient** - Control retry delay growth rate

<Info>
  Retry policies are core to Temporal's reliability guarantees. Configure them carefully to balance fault tolerance with resource usage.
</Info>

## Retry Policy Configuration

<ParamField path="initialInterval" type="duration" required>
  Delay before the first retry attempt

  Default: 1 second

  ```go theme={null}
  InitialInterval: time.Second
  ```
</ParamField>

<ParamField path="backoffCoefficient" type="float" required>
  Multiplier for retry delay on each attempt

  Default: 2.0

  ```go theme={null}
  BackoffCoefficient: 2.0 // Doubles delay each retry
  ```
</ParamField>

<ParamField path="maximumInterval" type="duration">
  Maximum delay between retries

  Default: 100x initial interval

  ```go theme={null}
  MaximumInterval: time.Minute * 5
  ```
</ParamField>

<ParamField path="maximumAttempts" type="int">
  Maximum number of retry attempts (0 = unlimited)

  Default: 0 (unlimited)

  ```go theme={null}
  MaximumAttempts: 10
  ```
</ParamField>

<ParamField path="nonRetriableErrorTypes" type="[]string">
  Error types that should not be retried

  ```go theme={null}
  NonRetriableErrorTypes: []string{"ValidationError", "PermissionDenied"}
  ```
</ParamField>

## Exponential Backoff Formula

Retry delay calculation:

```
retryDelay = min(
    initialInterval * (backoffCoefficient ^ attemptNumber),
    maximumInterval
)
```

### Example: Default Policy

With default settings (`initialInterval=1s`, `backoffCoefficient=2.0`, `maximumInterval=100s`):

| Attempt | Delay Calculation | Actual Delay      |
| ------- | ----------------- | ----------------- |
| 1       | 1s × 2^0 = 1s     | 1s                |
| 2       | 1s × 2^1 = 2s     | 2s                |
| 3       | 1s × 2^2 = 4s     | 4s                |
| 4       | 1s × 2^3 = 8s     | 8s                |
| 5       | 1s × 2^4 = 16s    | 16s               |
| 6       | 1s × 2^5 = 32s    | 32s               |
| 7       | 1s × 2^6 = 64s    | 64s               |
| 8       | 1s × 2^7 = 128s   | **100s** (capped) |
| 9       | 1s × 2^8 = 256s   | **100s** (capped) |

## Activity Retry Policies

Configure retries when scheduling activities:

<Tabs>
  <Tab title="Go">
    ```go theme={null}
    ao := workflow.ActivityOptions{
        StartToCloseTimeout: time.Minute * 10,
        RetryPolicy: &temporal.RetryPolicy{
            InitialInterval:    time.Second,
            BackoffCoefficient: 2.0,
            MaximumInterval:    time.Minute,
            MaximumAttempts:    5,
            NonRetriableErrorTypes: []string{
                "ValidationError",
            },
        },
    }
    ctx = workflow.WithActivityOptions(ctx, ao)

    err := workflow.ExecuteActivity(ctx, MyActivity, input).Get(ctx, &result)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const result = await proxyActivities<typeof activities>({
      startToCloseTimeout: '10m',
      retry: {
        initialInterval: '1s',
        backoffCoefficient: 2.0,
        maximumInterval: '1m',
        maximumAttempts: 5,
        nonRetriableErrorTypes: ['ValidationError'],
      },
    }).myActivity(input);
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    result = await workflow.execute_activity(
        my_activity,
        input,
        start_to_close_timeout=timedelta(minutes=10),
        retry_policy=RetryPolicy(
            initial_interval=timedelta(seconds=1),
            backoff_coefficient=2.0,
            maximum_interval=timedelta(minutes=1),
            maximum_attempts=5,
            non_retriable_error_types=["ValidationError"],
        ),
    )
    ```
  </Tab>
</Tabs>

## Workflow Retry Policies

Configure retries for workflows and child workflows:

```go theme={null}
// Start workflow with retry policy
workflowOptions := client.StartWorkflowOptions{
    ID:        "my-workflow-id",
    TaskQueue: "my-task-queue",
    RetryPolicy: &temporal.RetryPolicy{
        InitialInterval:    time.Second * 5,
        BackoffCoefficient: 2.0,
        MaximumInterval:    time.Hour,
        MaximumAttempts:    3,
    },
}

we, err := c.ExecuteWorkflow(context.Background(), workflowOptions, MyWorkflow)
```

<Warning>
  Workflow retries create a new workflow execution run. The workflow will restart from the beginning on each retry.
</Warning>

## Server-Side Configuration

Default retry policies can be configured in dynamic config:

```yaml theme={null}
# Dynamic config for default activity retry
frontend.defaultActivityRetryPolicy:
  InitialIntervalInSeconds: 1
  BackoffCoefficient: 2.0
  MaximumIntervalInSeconds: 100
  MaximumAttempts: 0

# Dynamic config for default workflow retry  
frontend.defaultWorkflowRetryPolicy:
  InitialIntervalInSeconds: 1
  BackoffCoefficient: 2.0
  MaximumIntervalInSeconds: 100
  MaximumAttempts: 0
```

## Non-Retriable Errors

Specify error types that should fail immediately without retry:

```go theme={null}
type ValidationError struct {
    message string
}

func (e *ValidationError) Error() string {
    return e.message
}

// Configure in retry policy
RetryPolicy: &temporal.RetryPolicy{
    NonRetriableErrorTypes: []string{
        "ValidationError",      // Match by type name
        "*errors.errorString",  // Match wrapped errors
    },
}
```

### Error Matching

Error type matching rules:

1. **Exact type name match** - `"ValidationError"` matches `ValidationError` type
2. **Package path match** - `"myapp/errors.ValidationError"` matches fully qualified type
3. **Wildcard match** - `"*ValidationError"` matches any package

<Accordion title="Implementation in History Service">
  Non-retriable error checking is implemented in `service/history/workflow/activity.go`:

  ```go theme={null}
  func isRetriable(err error, policy *RetryPolicy) bool {
      errorType := reflect.TypeOf(err).String()
      for _, nonRetriable := range policy.NonRetriableErrorTypes {
          if strings.HasSuffix(errorType, nonRetriable) {
              return false
          }
      }
      return true
  }
  ```
</Accordion>

## Retry Timeouts

Retries interact with activity and workflow timeouts:

### Activity Timeouts

<CardGroup cols={2}>
  <Card title="ScheduleToStart" icon="clock">
    Time from schedule to worker pickup. Retries reset this timeout.
  </Card>

  <Card title="StartToClose" icon="hourglass">
    Time for single attempt. Each retry gets full StartToClose timeout.
  </Card>

  <Card title="ScheduleToClose" icon="timer">
    Total time including all retries. Stops retry loop when exceeded.
  </Card>

  <Card title="Heartbeat" icon="heart-pulse">
    Heartbeat timeout. Retries reset on heartbeat timeout.
  </Card>
</CardGroup>

### Retry Until ScheduleToClose

```go theme={null}
ao := workflow.ActivityOptions{
    StartToCloseTimeout:    time.Minute,      // 1 minute per attempt
    ScheduleToCloseTimeout: time.Minute * 10, // 10 minutes total
    RetryPolicy: &temporal.RetryPolicy{
        InitialInterval: time.Second,
        MaximumAttempts: 0, // Unlimited
    },
}
```

Activity will retry until:

* ScheduleToCloseTimeout (10 minutes) is exceeded
* OR activity succeeds
* OR non-retriable error occurs

## Best Practices

<AccordionGroup>
  <Accordion title="Use appropriate backoff for service dependencies" icon="server">
    Match backoff to downstream service recovery time:

    * **Fast recovery** (seconds): `initialInterval=1s`, `backoffCoefficient=1.5`
    * **Slow recovery** (minutes): `initialInterval=30s`, `backoffCoefficient=2.0`
    * **Rate limited APIs**: `initialInterval=5s`, `maximumInterval=5m`
  </Accordion>

  <Accordion title="Limit retries for expensive operations" icon="dollar-sign">
    Set `maximumAttempts` for costly activities:

    ```go theme={null}
    RetryPolicy: &temporal.RetryPolicy{
        InitialInterval: time.Second * 5,
        MaximumAttempts: 3, // Only retry twice
    }
    ```
  </Accordion>

  <Accordion title="Mark validation errors as non-retriable" icon="shield-xmark">
    Don't waste resources retrying permanent failures:

    ```go theme={null}
    NonRetriableErrorTypes: []string{
        "ValidationError",
        "AuthenticationError",
        "AuthorizationError",
        "NotFoundError",
    }
    ```
  </Accordion>

  <Accordion title="Use ScheduleToClose to bound total retry time" icon="stopwatch">
    Prevent infinite retry loops:

    ```go theme={null}
    ao := workflow.ActivityOptions{
        ScheduleToCloseTimeout: time.Hour, // Max 1 hour of retries
        RetryPolicy: &temporal.RetryPolicy{
            MaximumAttempts: 0, // Unlimited attempts within 1 hour
        },
    }
    ```
  </Accordion>
</AccordionGroup>

## Monitoring Retry Behavior

Key metrics for retry monitoring:

* **activity\_task\_schedule\_to\_start\_latency** - Time waiting for worker (increases with retries)
* **activity\_execution\_failed** - Failed activity attempts (includes retries)
* **activity\_execution\_failed\_total** - Activities failed after all retries
* **activity\_retry\_count** - Number of retry attempts per activity

## Implementation Details

Retry logic is implemented in:

* **Activity retries**: `service/history/workflow/activity.go`
* **Workflow retries**: `service/history/workflow/mutable_state_impl.go`
* **Backoff calculation**: `common/backoff/retry.go`
* **Timer scheduling**: History Service timer queue

Retry state is persisted in workflow mutable state:

```go theme={null}
type ActivityInfo struct {
    Attempt          int32
    LastFailure      *failurepb.Failure
    ScheduledTime    *timestamppb.Timestamp
    RetryLastWorkerIdentity string
    // ...
}
```

## See Also

<CardGroup cols={2}>
  <Card title="Activities" href="/concepts/activities">
    Learn about activity execution and timeouts
  </Card>

  <Card title="Workflows" href="/concepts/workflows">
    Understand workflow execution model
  </Card>

  <Card title="History Service" href="/architecture/history-service">
    Deep dive into retry implementation
  </Card>
</CardGroup>
