🧊

Cloudflare Workersの内部時間は、非同期I/Oがあると進む

Cloudflare Workersでは、セキュリティの都合上、Date.now()などのタイミングを測ろうとする値はいつも同じ(WorkerへのI/Oの時点で固定)になってる。

Security model · Cloudflare Workers docs https://developers.cloudflare.com/workers/learning/security-model#step-1-disallow-timers-and-multi-threading

が、いつも何度でも絶対に固定値というわけではなく、実は非同期I/Oがあったときだけは進む。

なので、特定のケースにおいてはそのパフォーマンスを計測できるってわけ。

ダメな例

これは上記のドキュメントにもある進まない例。

let start = Date.now();
for (let i = 0; i < 1e6; i++) {
  doSpectreAttack();
}
let end = Date.now();

end - start; // 0

同期処理だと何をしても進まない。

let now = performance.now();

let wait = 10000000;
while (wait--) {}

performance.now() - now; // 0

どんだけ待とうが進まない。これをasyncな関数に包もうが、進まない。 await crypto.subtle.digest("SHA-256", data);とか、非同期のAPIを呼んだとしても、進まない。

どうしても同期処理を計測したい場合は、waitUntil()でWorkerの外に逃げた先でタイムスタンプを取って比較するしかない。

よい例

let start = Date.now();
await fetch(/* ... */)
let end = Date.now();

end - start; // ✌️

というように、外部へのI/Oがあったときはちゃんと進む。

R2とかKVへのアクセスも該当するので、R2とKVの.get()はどっちが速いかとかは計測できる。

performance.now()でもDate.now()でも一緒。console.time()は、エラーにはならないけど何もログに出なかったので、まだ使えない?(wrangler dev --remote時)