🧊

Cloudflare Workersで、128MB以上のレスポンスを返す

基本的には可能。だが、少しだけハマりどころがある。

メモリ制限

Limits · Cloudflare Workers docs https://developers.cloudflare.com/workers/platform/limits/#worker-limits

ここにあるように、そもそものWorkerの制限として、メモリは128MBまでというのがある。

これはどれだけ課金してようが関係なく、変えられない上限になってる。

デカいファイルを返したい

って場合はどうすれば?128MBじゃ足りない!と思うかもしれないが、別に難しいことはない。

たとえば、それがR2に保存してある場合。

const myLargeFile = await env.R2.get("key");

if (myLargeFile !== null)
  return new Response(myLargeFile.body, { /*...*/ });

というように、R2ObjectBodyReadableStreamになってるので、それをそのまま返すだけでいい。これなら128MB制限には引っかからない。

別のオリジンからfetch()で取得する場合も一緒。

const myLargeFile = await fetch(/* ... */);

return new Response(myLargeFile, { /* ... */ });

KVはそもそも25MBまでしか値を保存できないので、ストレートにこの問題で困ることはないはず。

加工したい場合

右から左に受け流すだけでいいなら、上記の方法でよい。

ただ、中身を加工したいとかそういう場合にだけ、メモリ上限の問題が出てくる。

const myLargeFile = await env.R2.get("key");

// Memory limit exceeded!
const blob = await myLargeFile.blob();

これを回避するためには、TransformStreamを使って逐次処理してやる必要がある。

https://developers.cloudflare.com/workers/runtime-apis/streams/transformstream/#identitytransformstream

Cloudflare Workersのランタイムには、

  • TransformStream
  • IdentityTransformStream

という2つの実装が存在するけど、特別な理由がなければ後者を使う。よりSpce準拠な挙動になってるとのこと。

Cloudflare Workersでそんなやりたいことあるか?とは思うけど・・・。

ちなみに、加工する対象がHTMLなのであれば、HTMLRewriterが使える。

Docsにも一応書いてある

Streams - Runtime APIs · Cloudflare Workers docs https://developers.cloudflare.com/workers/runtime-apis/streams/

書いてあるけど、単にパススルーするだけのコード例が大きく載ってて(しかもIdentityTransformStreamじゃないほうで)、本文ではなく注釈風に、「加工しないならそのまま返せばいい」って書いてある。

もしかして、ReadableStreamでそのまま返すのではダメで、一見無意味に見えるこのコードが必要になるケースあんの?!って、普通にちょっと混乱した。