> ## Documentation Index
> Fetch the complete documentation index at: https://s2.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Retries + Timeouts

> Configure S2 SDK timeouts, retry backoff, and append retry policy.

## Timeouts

SDKs support configuring connection and request timeouts:

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    const client = new S2({
    	accessToken: accessToken,
    	connectionTimeoutMillis: 5000,
    	requestTimeoutMillis: 10000,
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    client = S2(
        access_token,
        timeout=Timeout(
            connection=timedelta(seconds=5),
            request=timedelta(seconds=10),
        ),
    )
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    client := s2.New(accessToken, &s2.ClientOptions{
    	ConnectionTimeout: 5 * time.Second,
    	RequestTimeout:    10 * time.Second,
    })
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    let client = S2::new(
        S2Config::new(access_token)
            .with_connection_timeout(Duration::from_secs(5))
            .with_request_timeout(Duration::from_secs(10)),
    )?;
    ```
  </Tab>
</Tabs>

* **Connection timeout**: Maximum time to wait for a TCP connection to be established. This is a "fail fast" timeout that aborts slow connections early.
* **Request timeout**: Maximum time to wait for a non-streaming request to complete. For [append sessions](/sdk/appending#append-session), this value is also used to determine the SDK-enforced timeout for an individual batch append to be acknowledged.

## Retry Behavior

SDKs automatically retry transient failures using exponential backoff with jitter.

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    const client = new S2({
    	accessToken: accessToken,
    	retry: {
    		maxAttempts: 5,
    		minBaseDelayMillis: 100,
    		maxBaseDelayMillis: 2000,
    	},
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    client = S2(
        access_token,
        retry=Retry(
            max_attempts=5,
            min_base_delay=timedelta(milliseconds=100),
            max_base_delay=timedelta(seconds=2),
        ),
    )
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    client := s2.New(accessToken, &s2.ClientOptions{
    	RetryConfig: &s2.RetryConfig{
    		MaxAttempts:  5,
    		MinBaseDelay: 100 * time.Millisecond,
    		MaxBaseDelay: 2 * time.Second,
    	},
    })
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    let client = S2::new(
        S2Config::new(access_token).with_retry(
            RetryConfig::new()
                .with_max_attempts(NonZeroU32::new(5).unwrap())
                .with_min_base_delay(Duration::from_millis(100))
                .with_max_base_delay(Duration::from_secs(2)),
        ),
    )?;
    ```
  </Tab>
</Tabs>

### Append Retry Policy

Retrying appends requires care: if an append succeeds but the acknowledgement is lost (e.g., due to a network timeout), retrying would create duplicate records in a stream.

The `appendRetryPolicy` setting controls how to react in this situation, by treating append retries as a special case.

| Policy          | Behavior                                                           |
| --------------- | ------------------------------------------------------------------ |
| `all` (default) | Retry all failed appends. Duplicates are possible.                 |
| `noSideEffects` | Only retry append failures which could not have had a side effect. |

Using `noSideEffects` means that, in the event of a failure, the caller will manually need to verify whether or not the append succeeded (e.g., by reading or otherwise inspecting the state of the stream).

<Tip>
  To write exactly-once in single-writer setups, append with a `matchSeqNum` precondition. See [concurrency control](/concepts/concurrency-control) for details.

  For multi-writer setups, include dedupe metadata such as a writer ID and per-writer idempotency key, then deduplicate later. This is touched upon in [this blog post](https://s2.dev/blog/patterns).
</Tip>

## Configuration Reference

### Timeout Settings

| Setting            | Default   | Description                          |
| ------------------ | --------- | ------------------------------------ |
| Connection timeout | 3 seconds | Max time to establish TCP connection |
| Request timeout    | 5 seconds | Max time for request completion      |

### Retry Settings

| Setting             | Default  | Description                                                   |
| ------------------- | -------- | ------------------------------------------------------------- |
| Max attempts        | 3        | Maximum retry attempts                                        |
| Min base delay      | 100 ms   | Minimum base delay for exponential backoff                    |
| Max base delay      | 1 second | Maximum base delay (actual delay with jitter can be up to 2x) |
| Append retry policy | `all`    | How to handle append retries when duplication is possible     |
