RORK LABEN
FREETRY — Rorkが「Rork Maxを期間限定で無料で試せるようにした」とXで告知しました。$200/月のプランに、費用を先に払わずに触れる機会ですONESHOT — Rork MaxはiPhone・Watch・iPad・TV・Vision Pro向けのアプリをほぼワンショットで生成すると謳い、ARと3Dを使うものまで対象に挙げていますXCODE — 「Xcodeを置き換えるWebサイト」を掲げ、実機インストールは1クリック、App Store提出は2クリック。裏側はSwiftとClaude Code、OpusですPAPERLINE — Rorkはアプリビルダーの Paperline を買収し、エンジニアリング人材の獲得に向けて今後も買収を続ける方針を示していますSKILLS — GitHubのapp-store-connect-cli-skillsが7月9日に更新。提出まわりの開発者ツールに手が入り続けていますMARKET — Gartnerは2026年末までに新規アプリの75%がローコードまたはノーコードで作られると見込んでいます。2020年は25%未満でしたFREETRY — Rorkが「Rork Maxを期間限定で無料で試せるようにした」とXで告知しました。$200/月のプランに、費用を先に払わずに触れる機会ですONESHOT — Rork MaxはiPhone・Watch・iPad・TV・Vision Pro向けのアプリをほぼワンショットで生成すると謳い、ARと3Dを使うものまで対象に挙げていますXCODE — 「Xcodeを置き換えるWebサイト」を掲げ、実機インストールは1クリック、App Store提出は2クリック。裏側はSwiftとClaude Code、OpusですPAPERLINE — Rorkはアプリビルダーの Paperline を買収し、エンジニアリング人材の獲得に向けて今後も買収を続ける方針を示していますSKILLS — GitHubのapp-store-connect-cli-skillsが7月9日に更新。提出まわりの開発者ツールに手が入り続けていますMARKET — Gartnerは2026年末までに新規アプリの75%がローコードまたはノーコードで作られると見込んでいます。2020年は25%未満でした
記事一覧/AIモデル
AIモデル/2026-07-17上級

3分の動画だけが失敗する — Rork の動画解析をワーカー経由から端末直送に引き直す

Gemini Files API に動画を渡す経路を、Cloudflare Workers 中継から端末直送へ引き直した記録です。128MB のメモリ上限に当たる仕組み、resumable upload の発行だけをサーバーに残す実装、解像度とフレームレートで請求を決める判断までをまとめます。

Rork515Gemini7Files API動画解析Cloudflare Workers24Expo149個人開発185

プレミアム記事

手元の iPhone で撮った 28 秒のテスト動画は、何度送っても通りました。解析結果も期待どおりに返ってきます。

ところが友人に頼んで撮ってもらった 3 分の動画を送った途端、アップロードが返ってこなくなりました。エラーメッセージらしいメッセージもなく、しばらく待つと 500 が返るだけです。

最初はモデル側の問題を疑いました。動画が長すぎるのか、フォーマットが違うのか。ログを追って分かったのは、そもそも Gemini に届く前の段階で落ちていたということです。落ちていたのは推論ではなく、動画の通り道でした。

28 秒は通るのに、3 分で止まる

当時の構成は、素直といえば素直なものでした。

Expo アプリで動画を選び、Cloudflare Workers に multipart で送り、Worker が Gemini の Files API へ中継します。API キーをアプリに埋め込みたくなかったので、サーバーを1枚挟んでいたわけです。個人開発でバックエンドを持たずに済ませたいとき、Workers は魅力的な選択肢でした。

Worker 側のコードは、こんな形をしていました。

// ❌ 当時の実装 — 動画がまるごと Worker のメモリに載る
async function handleVideoUpload(request: Request, env: Env): Promise<Response> {
  const formData = await request.formData();
  const videoFile = formData.get('video') as File;
 
  // ここで動画の全バイトが Worker のヒープに展開される
  const arrayBuffer = await videoFile.arrayBuffer();
 
  const initResponse = await fetch(`${UPLOAD_URL}?key=${env.GEMINI_API_KEY}`, {
    method: 'POST',
    headers: {
      'X-Goog-Upload-Protocol': 'resumable',
      'X-Goog-Upload-Command': 'start',
      'X-Goog-Upload-Header-Content-Length': arrayBuffer.byteLength.toString(),
      'X-Goog-Upload-Header-Content-Type': videoFile.type,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ file: { display_name: videoFile.name } }),
  });
 
  const uploadUri = initResponse.headers.get('X-Goog-Upload-URL');
 
  // 受け取った全バイトを、そのまま Google へ送り直す
  return fetch(uploadUri!, {
    method: 'POST',
    headers: {
      'Content-Length': arrayBuffer.byteLength.toString(),
      'X-Goog-Upload-Offset': '0',
      'X-Goog-Upload-Command': 'upload, finalize',
    },
    body: arrayBuffer,
  });
}

await videoFile.arrayBuffer() の一行が、すべてでした。

動画がワーカーを通り抜けていた

Cloudflare Workers は、1 つの isolate あたり 128MB のメモリを上限としています。これは JavaScript のヒープと WebAssembly の確保分を合わせた値で、有料プランに上げても増えません。しかも上限は「1リクエストあたり」ではなく「isolate あたり」です。

一方で、リクエストボディのサイズ上限は Free プランで 100MB あります。つまり「100MB の動画は受け取れてしまうが、それをメモリに展開する余地はない」という構造になっていました。

iPhone で撮った動画のサイズを測ってみると、こうです。

撮影設定長さ実測サイズarrayBuffer 後の挙動
1080p / 30fps28秒約 52MB通る
1080p / 30fps1分10秒約 130MB413 が返る
720p / 30fps3分約 96MB断続的に 500
4K / 60fps30秒約 190MB413 が返る

3 分の 720p が最も厄介でした。96MB はボディ上限の 100MB を下回るので受理されます。けれど 96MB をヒープに載せた時点で、128MB のうち大半を1本の動画が占めます。同じ isolate に別のリクエストが相乗りしていれば、そこで超えます。

だから「断続的に」失敗していたのです。手元で1人で試している間は通り、複数人が同時に触ると落ちる。再現条件が掴めなかった理由がここにありました。

さらに、通ったところで無駄が残ります。動画は端末から Cloudflare へ上り、Cloudflare から Google へもう一度上る。同じバイト列が 2 回ネットワークを流れ、その往復のあいだ Worker の CPU 時間を占有し続けます。中継する意味があったのは API キーを隠すことだけでした。

キーを隠したいだけなら、動画そのものを通す必要はありません。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
動画を Worker の arrayBuffer に載せた瞬間に 128MB のメモリ上限へ当たる仕組みと、端末直送に切り替えるまでの経路設計
resumable upload の開始だけをサーバーに残し、API キーを配らずに端末から直接送る Worker / Expo 両側の実装コード
media_resolution を low に落とし fps を下げることで、動画1秒あたりのトークンを約300から約100へ削る判断基準
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

AI モデル2026-07-05
家計アプリのAI分類が『その他』に飲まれていくとき — 静かに崩れる支出仕分けを計測して立て直す運用メモ
Rork で作ったAI家計アプリの支出自動分類は、リリース直後は当たっていても数ヶ月かけて静かに精度が落ち、月末アドバイスまで狂わせます。確信度と分類分布を計測してドリフトを先回りする運用手順を、動くコードとともにまとめました。
AI モデル2026-06-27
Rork で作ったアプリを収益化する — 広告・サブスク・フリーミアムの選び方と踏み込みどころ
Rork で作ったアプリの収益化を、広告・サブスク・フリーミアム・買い切りの選び方から実装の勘どころまで整理します。AdMob のフォーマット段階導入、ad-free を単一の真実源にする設計、価格アンカリングまで、個人開発の現場感で書きました。
AI モデル2026-06-19
Rork Max に月 $200 を払う前に、Expo でどこまで届くかを3階層で見極める
ウィジェットや Live Activities が欲しくなると Rork Max が視野に入りますが、その多くは標準 Rork の Expo 構成でも届きます。機能ごとに「Expo で届く・自作モジュールで届く・Max が現実解」の3階層に分け、課金前に実機で見極める手順を整理しました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →