Durable Object の呼び出し、もう自分でリトライ書かなくていいかも?
おつかれさま、しぃちゃんだよ!
Cloudflare Changelog今日は Durable Objects を使っている人に朗報だよ。リトライのコードが減るかもしれないの!
なにが発表されたの?
Cloudflare の Changelog で、Durable Object への fetch() と RPC の呼び出しが、到達前に再試行可能なエラーで失敗したとき、ランタイムが自動で再試行するようになったと告知されたよ。呼び出し元が Worker でも別の Durable Object でも対象だよ。
今までどうだったの?
ネットワークが一瞬途切れるような短い障害でも、呼び出し側のコードにリトライのループを書く必要があったの。今回の変更で、そうした短い障害ではリトライループが要らなくなるよ。
これで何が変わるの?
- 短いネットワーク障害のために、自前の再試行コードを書かなくてよくなる
- 冪等なメソッドだけを選んで、安全に再実行できるようにできる
深く潜ってみよう
デフォルトの動き
- 1 回の呼び出しにつき、最大 4 回まで再試行する
- 最初の呼び出しの開始から 10 秒を超えて始まる再試行はない
- Durable Object のコードが投げたエラーは再試行しない
.overloadedが true のエラーも再試行しない- 接続が切れて、Durable Object が呼び出しを受け取ったか分からないときも再試行はするよ。ただし最初の試行が届いていたら、Durable Object 側が再試行を拒否する
メソッドの二重実行について
再試行のせいでメソッドが 2 回走ることは、基本的にないの。2 回走ってよいメソッドだけ、cloudflare:durable-objects の retryable() で印を付けるよ。冪等なメソッドだけに付けて、加算のような冪等でないメソッドには付けないでね。
import { DurableObject } from "cloudflare:workers";
import { retryable } from "cloudflare:durable-objects";
export class Inventory extends DurableObject {
static {
retryable(this.prototype.setStock);
}
// 冪等: もう一度実行しても同じ在庫数になる
async setStock(sku, count) {
await this.ctx.storage.put(sku, count);
}
// 再試行しない: もう一度実行するとさらに 1 つ減ってしまう
async decrementStock(sku) {
const current = (await this.ctx.storage.get(sku)) ?? 0;
await this.ctx.storage.put(sku, current - 1);
}
}
スタブごとの設定
get() や getByName() に retry オプションを渡すと調整できるよ。
maxRetries: 0 から 10timeoutMs: 500 から 60,000 ミリ秒
const stub = env.INVENTORY.getByName("warehouse-7", {
retry: { maxRetries: 2, timeoutMs: 5000 },
});
気をつけたいこと
- すでに自前で再試行しているコードは、1 回ごとの試行の中でランタイムの再試行も走ることになる。自前の試行回数を減らすか、自前で再試行したいスタブには
maxRetries: 0を設定してね retryable()とretryオプションを使うには Wrangler 4.158.0 以降が必要
まとめ
- Durable Object への
fetch()と RPC が、到達前の再試行可能なエラーで自動再試行される - デフォルトは最大 4 回、開始から 10 秒以内
- 冪等なメソッドだけ
retryable()で印を付ける retryオプションで回数と時間を調整できる(Wrangler 4.158.0 以降)
Durable Objects に自前のリトライ処理を書いてきた人は、コードを見直すチャンスだよ!