コンテンツにスキップ

Durable Objectにおけるメモリ内状態

メモリ内状態とは、各Durable Objectが特定の時点で1つのアクティブインスタンスを持つことを意味します。そのDurable Objectに送信されたすべてのリクエストは、その同じインスタンスによって処理されます。メモリにいくつかの状態を保存することができます。

Durable Object内の変数は、Durable Objectがメモリから追い出されない限り、状態を維持します。

一般的なパターンは、永続ストレージからDurable Objectを初期化し、最初にアクセスされたときにインスタンス変数を設定することです。将来のアクセスは同じDurable Objectにルーティングされるため、永続ストレージに対してさらに呼び出しを行うことなく、初期化された値を返すことが可能です。

export class Counter {
constructor(state, env) {
this.state = state;
// `blockConcurrencyWhile()`は、初期化が完了するまで
// リクエストが配信されないことを保証します。
this.state.blockConcurrencyWhile(async () => {
let stored = await this.state.storage.get("value");
// 初期化後、将来の読み取りはストレージにアクセスする必要がありません。
this.value = stored || 0;
});
}
// クライアントからのHTTPリクエストを処理します。
async fetch(request) {
// storageではなくthis.valueを使用します
}
}

特定のDurable Objectのインスタンスは、同じWorkerコードで定義された他のインスタンスとグローバルメモリを共有することがあります。

上記の例では、インスタンス変数this.valueの代わりにグローバル変数valueを使用することは不正確です。2つの異なるCounterのインスタンスはそれぞれthis.valueのための独自のメモリを持ちますが、グローバル変数valueのためのメモリを共有する可能性があり、予期しない結果を招くことがあります。このため、グローバル変数は避けるのが最善です。

state.blockConcurrencyWhile() メソッド

state.blockConcurrencyWhile()メソッドは、クリティカルセクションが実行されている間、オブジェクト内の並行性をブロックし、順序を保証します。

state.blockConcurrencyWhile(callback)の戻り値の型はPromise<T>であり、ここでTcallbackの戻り値の型です。このメソッドは、コールバック(非同期である可能性があります)を実行し、コールバックが完了するまでオブジェクトに他のイベントが配信されるのをブロックします。

これにより、I/O(例えばfetch())を実行するコードを実行する際に、オブジェクトの状態が並行イベントの結果として予期せず変更されないことが保証されます。コールバック自体の一部として明示的に開始されなかったすべてのイベントはブロックされます。

ブロックされるイベントには、新しい受信リクエストや、コールバックの外部で開始された送信リクエスト(例えばfetch())への応答が含まれます。コールバックが完了すると、これらのイベントが配信されます。

state.blockConcurrencyWhile()は、リクエストが配信される前に実行する必要がある初期化を行うために、オブジェクトのコンストラクタ内で役立ちます。このメソッドは、コンストラクタの外でも役立つ場合があります。例えば、ストレージ操作のシーケンスを実行したい場合や、並行アクションがストレージの状態を変更するのを避けたい場合は、state.blockConcurrencyWhile()コールバック内で操作のシーケンスを実行します。

コールバックが例外をスローすると、オブジェクトは終了し、リセットされます。これにより、何かが予期せず失敗した場合にオブジェクトが初期化されていない状態に留まることがないようにします。この動作を避けるために、コールバックの本体をtry...catchブロックで囲み、例外をスローできないようにします。

state.blockConcurrencyWhile()はすぐに効果を発揮し、現在実行中のイベントとstate.blockConcurrencyWhile()コールバック内で開始されたI/Oを除くすべてを一時停止します。コールバックによって返される値は、state.blockConcurrencyWhile()自体によって返される値になります。

追い出しをシミュレートするには、state.blockConcurrencyWhile()を使用します。コールバック内で例外をスローします。例外をスローすると、システムはメモリ内オブジェクトを再作成しますが、耐久性のあるストレージには影響しません。state.blockConcurrencyWhile()内の未捕捉の例外は、アクターを壊します。

クリティカルセクションでデッドロックを防ぐために、state.blockConcurrencyWhileに渡されるコールバックには30秒のタイムアウトがあります。このタイムアウトが超過すると、Durable Objectはリセットされます。一般的に、blockConcurrencyWhile()内のクリティカルセクションはできるだけ短くすることが良いプラクティスです。