# Automatic Retries for Durable Object Calls: Maybe No More Hand-Written Retry Loops?

Hi, it's Shii-chan!

Here is good news for anyone using Durable Objects: you may be able to delete some retry code!

## What was announced?

In the Cloudflare Changelog, the runtime now retries `fetch()` and RPC calls to a Durable Object when they fail with a retryable error before reaching it. This applies whether the caller is a Worker or another Durable Object.

## The story so far

Even for short disruptions such as a brief network interruption, you had to write a retry loop in the calling code. With this change, short disruptions no longer need one.

## What changes

- You don't need your own retry code for brief network problems
- You can opt specific idempotent methods in to safe re-execution

## Dive Deep

**Default behavior**

- Up to four retries per call
- No retry starts more than 10 seconds after the initial call starts
- Errors thrown by your Durable Object code are not retried
- Errors with `.overloaded` set to true are not retried
- If the connection drops and the runtime can't tell whether the Durable Object received the call, it still retries, but the Durable Object rejects the retry if the first attempt arrived

**Methods and double execution**

A method never runs twice because of a retry unless you mark it with `retryable()` from `cloudflare:durable-objects`. Only mark idempotent methods, and leave things like increments unmarked.

```js
import { DurableObject } from "cloudflare:workers";
import { retryable } from "cloudflare:durable-objects";

export class Inventory extends DurableObject {
  static {
    retryable(this.prototype.setStock);
  }

  // Idempotent: running it again leaves the same stock count
  async setStock(sku, count) {
    await this.ctx.storage.put(sku, count);
  }

  // Not retryable: running it again would remove another unit
  async decrementStock(sku) {
    const current = (await this.ctx.storage.get(sku)) ?? 0;
    await this.ctx.storage.put(sku, current - 1);
  }
}
```

**Per-stub settings**

Pass a `retry` option to `get()` or `getByName()`:

- `maxRetries`: 0 to 10
- `timeoutMs`: 500 to 60,000 milliseconds

```js
const stub = env.INVENTORY.getByName("warehouse-7", {
  retry: { maxRetries: 2, timeoutMs: 5000 },
});
```

**Things to check**

- If your code already retries, each of your attempts now includes the runtime's retries. Lower your own attempt count, or set `maxRetries: 0` on stubs where your code handles retries
- Using `retryable()` and the `retry` option requires Wrangler 4.158.0 or later

## Wrap-up

- `fetch()` and RPC calls to a Durable Object are retried automatically on retryable errors before reaching it
- Defaults are up to four retries within 10 seconds of the start
- Mark only idempotent methods with `retryable()`
- Tune with the `retry` option (Wrangler 4.158.0 or later)

If you've been writing your own retries around Durable Objects, now is a good time to review that code!
