このセクションでは、Durable Object のライフサイクルを説明します。
Durable Object を使うには、Durable Object Stub を作成する必要があります。 Stub を作成しただけでは Durable Object にリクエストは送られず、Durable Object はまだインスタンス化されません。 Durable Object Stub のメソッドを呼び出したときだけリクエストが送られ、ライフサイクルが始まります。
const stub = env.MY_DURABLE_OBJECT.getByName("foo");
// Now the request is sent to the remote Durable Object.
const rpcResponse = await stub.sayHello();Durable Object は、任意の時点で次のいずれかの状態になります。
| 状態 | 説明 |
|---|---|
| Active, in-memory | Durable Object がメモリ上で動作し、受信リクエストを処理します。 |
| Idle, in-memory non-hibernateable | Durable Object は次の受信リクエスト / イベントを待ちますが、休止(hibernation)の条件を満たしていません。 |
| Idle, in-memory hibernateable | Durable Object は次の受信リクエスト / イベントを待ち、休止の条件を満たしています。休止するタイミングはランタイムが決めます。現在は、この状態で 10 秒間操作がないあとです。 |
| Hibernated | Durable Object はメモリから取り除かれます。休止した WebSocket 接続は維持されます。 |
| Inactive | Durable Object はホストプロセスから完全に取り除かれ、コールドスタートが必要になることがあります。すべての Durable Object の初期状態です。 |
Durable Object は、これらの状態のあいだを次のように遷移します(各状態は角丸の四角形です)。
Durable Object が動いていない場合、最初の受信リクエストまたはイベント(アラームなど)は、Durable Object クラスの constructor() を実行し、続けて呼び出された関数を実行します。
この時点で Durable Object は active in-memory 状態です。
受信リクエストまたはイベントをすべて処理したあと、Durable Object は数秒間、休止可能な状態または不可能な状態で、メモリ上のアイドルになります。
休止は、次の条件が すべて 真の場合にだけ起きます。
setTimeout/setIntervalのスケジュール済みコールバックがないこと。休止後にコールバックを再作成できないためです。- 進行中の待機中
fetch()がないこと。I/O 待ちと見なされるためです。 - WebSocket 標準 API を使っていないこと。
- リクエスト / イベントの処理がまだ続いていないこと。休止すると、そのリクエストに最終的に応答を返す非同期関数の追跡を失うためです。
- アクティブな外向き TCP ソケット(
connect())または外向き WebSocket 接続がないこと。
受信リクエストまたはイベントがなく、上記の条件をすべて満たしてから 10 秒後に、Durable Object は hibernated 状態へ遷移します。
上記のいずれかの条件が偽の場合、Durable Object はメモリ上に残り、idle, in-memory, non-hibernateable 状態になります。
hibernated 状態で受信リクエストまたはイベントがあると、constructor() が再度走り、Durable Object は active, in-memory 状態へ遷移して呼び出された関数を実行します。
idle, in-memory, non-hibernateable 状態では、70〜140 秒間操作がない(受信リクエストまたはイベントがない)と、Durable Object はメモリから、場合によっては Cloudflare ホストからも完全にエビクションされ、inactive 状態へ遷移します。
hibernated 状態のオブジェクトは WebSocket クライアントとの接続を維持します。ランタイムは、オブジェクトを inactive 状態へいつ遷移させるか(たとえば別ホストへ移す判断)を決めます。このときライフサイクルが再開します。
次の受信リクエストまたはイベントで、サイクルが再び始まります。
Durable Object はときどきシャットダウンし、オブジェクトは再起動します。そのとき Durable Object クラスのコンストラクターが走ります。理由はさまざまです。次のような場合があります。
- コード更新を伴う新しい Worker の デプロイ
- 上記の状態遷移に従い、オブジェクトへのリクエストがないこと
- Workers ランタイムシステムの Cloudflare 側更新
- オブジェクトのホスト先に関する Workers ランタイムの判断
Durable Object がシャットダウンすると、オブジェクトインスタンスは自動的に再起動し、新しいリクエストは新しいインスタンスへルーティングされます。進行中のリクエストは次のように扱われます。
- HTTP と RPC リクエスト: 進行中のリクエストは、Durable Object のストレージにアクセスしなければ完了できます。リクエストが Durable Object のストレージにアクセスしようとすると、即座に停止し、Durable Objects のグローバル一意性を保つためにエラーを返します。Worker ランタイムシステムの更新時は、進行中のリクエストに完了まで最大 30 秒あります。
- WebSocket 接続: シャットダウン中、WebSocket リクエストは自動的に終了します。新しいインスタンスができるだけ早く接続を引き継げるようにするためです。
- その他の呼び出し(email、cron): その他の呼び出しは HTTP リクエストと同様に扱われます。
Durable Object を使うサービスは、Durable Object がシャットダウンする可能性を踏まえて設計することが重要です。
Durable Object のコードを更新すると、Worker と Durable Object は結果整合的にグローバルへ公開されます。これにより Durable Object はシャットダウンし、上記の動作になります。更新によって、ある場所では新しいバージョンの Worker にリクエストが届き、別の場所では以前のバージョンの Durable Object を呼び出している状況も起き得ます。このシナリオへの対処は コード更新 を参照してください。
Durable Objects は、デプロイ、非アクティブ、ランタイムの判断により、いつでもシャットダウンすることがあります。シャットダウンフック(提供されていません)に頼るのではなく、状態を少しずつ書き込むようにアプリケーションを設計してください。
シャットダウン前に実行されるシャットダウンフックやライフサイクルコールバックは提供していません。Cloudflare は、こうしたフックがすべてのケースで実行されることを保証できないためです。また、外部ソフトウェアがこうした(信頼性のない)フックに過度に依存するおそれもあります。
シャットダウンフックに頼る代わりに、ストレージへ定期的に書き込めば、シャットダウンから安全に回復できます。
たとえば、データのストリームを処理して進捗を保存する必要がある場合は、最後にまとめて永続化するのではなく、処理の途中で位置をストレージに書き込みます。
// Good: Write progress as you go
async processData(data) {
data.forEach(async (item, index) => {
await this.processItem(item);
// Save progress frequently
await this.ctx.storage.put("lastProcessedIndex", index);
});
}こうした書き方は直感に反するように感じるかもしれませんが、Durable Object のストレージ書き込みは高速で同期的なので、パフォーマンスを大きく気にせず状態を永続化できます。
この方法なら、Durable Object が予期せずシャットダウンしても、任意の地点から安全に再開できます。