kikushun.com の初週
iPhone から放り込んだ文字・写真・音声・動画を Claude Code が読んで、記事と SNS の下書きにするところまでを 2 日で作りました。作ったものより、途中でぶつかった R2 の上限と、2.55GB の動画が 32 パート目で止まった話のほうが役に立つと思うので、そっちを書きます。
全体の構成
生のメディアは GitHub に置かず R2 に入れて、公開する画像だけ別のバケットに出しています。Claude Code は MacBook から Inbox を読み、GitHub への push で Actions が起動してデプロイされる仕組みです。
ぶつかった上限
先に知っていれば設計が変わっていた数字です。
| 対象 | 値 | 効いてくるところ |
|---|---|---|
| R2 の multipart | 1 パート 5 MiB〜5 GiB、最大 10,000 パート | 送れる最大サイズはパート長しだい(20 MiB なら 195 GiB) |
| 1 パートの大きさ | 20 MiB | パートは Worker を経由して一度メモリに載るため |
| 添付の上限 | 5 GiB | R2 の制約ではなく、こちらで決めた値 |
最初は 2 GiB にしていて、2.55GB の動画が validation_error の一言で弾かれました。zod のメッセージが英語のまま画面に出ていなかったので、何が起きたのか不明でした。。。上限を 5 GiB に上げ、/api/health で limits を返して、PWA 側はファイルを選んだ時点で上限を見るようにしました。
2.55GB の動画が 32 パート目で止まる
上限を上げたら、今度は送信が途中で止まりました。画面は送信中の表示のままで、遅いのか死んだのかも分かりませんでした。
原因は、パートの PUT にタイムアウトも再送も無かったことです。iPhone の画面ロックで fetch が宙に浮くと、そのまま永遠に待っていました。
直したのは 4 点です。
- 120 秒のタイムアウトを付けて、通信断・タイムアウト・5xx は最大 6 回まで指数バックオフで再送
- 4xx は何度やっても同じなので即やめる
- 送信中は Screen Wake Lock を取る(裏に回って解放されたら、戻ったときに取り直す)
- 進捗を「32 / 130 パート (25%)」と再送回数で出す。送信中の再読込には確認ダイアログ
再送して大丈夫なのは、R2 の multipart が同じパート番号の上書きを許すからです。途中まで送ったパートを捨てて、最初からやり直す必要はありません。
2 日間の内訳
9/13 は土台。Astro 7 の静的サイト(Blog / Projects / Log / About)、Hono の Inbox Worker(D1 / R2 / Cloudflare Access / Whisper 文字起こし)、iPhone から投げる PWA、GitHub Actions の CI と Deploy、写真の公開経路(exiftool で EXIF 除去を検証してから配信)、動画加工スクリプト、YouTube の軽量埋め込みまで。
9/14 は運用の作り直し。develop ブランチを廃止して、生成物に初見レビュー必須の品質ゲートを付けました。そのあとが上の 2.55GB の話です。