2026年9月のふりかえりです。 ひきつづき B 社(週5日) での稼働となります。

※前回に続いて、Slackの#times_yagitaチャンネルの内容をClaude Codeに読ませて記事化しています。

B 社

8 月に中長期計画に沿って立ち上げた各エピックが、9 月はそれぞれ実装フェーズに入ってきた、という1か月でした。 大きく分けると、ストアフロントの Next.js 化の Phase 0、バッチのコンテナ化、dev/staging 環境の作り直し、そして調査の過程で出てくる年季の入った不具合の後始末、という感じです。

ストアフロントの Next.js 化(Phase 0)

9 月から、公開側のストアフロントを Rails から Next.js へ段階的に移していくエピックが動き出しました。 まずは Phase 0 として、移行先の土台と、既存 Rails 側に必要な API や前提を揃えるところをやっています。

  • 新しいリポジトリと Next.js のスケルトン・CI を用意して、CDK スタックを新設し dev へデプロイ、監視の配線まで済ませました。
    • 月の中ごろには本番用の CDK スタック(Fargate / ターゲットグループ / 監視 / CD)も用意しています。
  • Aurora の reader への接続、DB スキーマからの型生成パイプライン、Rails 側と Next.js 側で共有するテーブルの「契約台帳」の初版を作りました。
    • あわせて、契約しているテーブルのスキーマが変わったら検知できるように、スキーマ契約のスナップショット spec を既存リポジトリ側に入れています。2 つのアプリが同じ DB を読む構成なので、ここは早めに安全網を張っておきたかったところです。
  • 本番の ALB が CDK 管理外(手管理)だったので、ターゲットグループ・リスナールールの追加/切替/ロールバック手順を整備しました。
  • Next.js 側から使う API として、ログイン状態の JSON API と最短お届け日の JSON API を Rails 側に新設しました。
  • ヘッダー/フッターのカテゴリメニュー構造がコードと設定に散らばっていたので、DB 化して単一ソースにしました。
    • ……のですが、その後「なんか全体的にパフォーマンス落ちてる感じがする」となり、調べるとメニュー描画が N+1 になっていて p95 を +45% 悪化させていました。すぐに潰しています。
  • 移行の効果を測るために、Rails 版の LP に web-vitals → GA4 の計装を先行投入して、before の分布を取り始めました。

依存関係のある issue が多いので、月初に進め方のフローを図にして共有してから着手しました。 どれがどの Phase の前提になっているかが見えていると、並列に進めるときの迷いが減ります。

バッチのコンテナ化

8 月に設計・分解したコンテナ化のエピックのうち、バッチ部分が進みました。

  • 共通前提として置いていた「排他制御を flock から MySQL の GET_LOCK へ」「バッチのログの出口と失敗検知をコンテナ前提へ」が完了しました。
  • 新しいバッチホスト(docker + cron/systemd + Datadog Agent)を立てて、デプロイ経路と schedule.rb を docker run 化し、48 本のジョブを段階的に移していく段階に入っています。
  • cron ジョブ台帳に runner を足して schedule.rb との対応を固定し直したり、owner の記入と tier2/3 の監視を展開したりと、台帳まわりも育てました。

レポートバッチの整理

8 月に見つけた「件数 1 つのために毎日 30MB」のような話の延長で、レポート生成バッチをまとめて棚卸ししました。

  • 未使用のレポート 4 クラスの生成を止めて、report_job_short を 3.6 時間 → 1.8 時間(−47.8%)にしました。
  • report_job_all が 59.4 時間(!)かかっていたので、生 SQL 化と N+1 解消で 1 行あたりの単価を下げて数時間に短縮しました。
  • 死蔵していたレポート用テーブル 30 本(約 3.0GB)を退避したうえで期限付きで DROP し、レポートクラスを消すときに本番テーブルも落とす運用を整備しました。3 年放置されていたものの再発防止です。
  • 2021 年のボット流入で 118.6 万行入っていたテーブルについても、保持方針と再発防止を決めました。

dev/staging 環境の作り直し

月の後半はこれが一番大きかったです。 dev ホスト群を stg1〜stg10 の番号プールにして、全体で 16 環境の体制にする、という話を進めました。

  • そもそも dev ホストが 1 台壊れると作り直せない状態だったので、まずゴールデン AMI を焼きました。
  • CDK スタックを作って stg1 を 1 台建て、増台が CDK 1 行で済むようにしています。
    • Google OAuth の redirect URI を stg1〜stg10 分先行登録したり、ホスト台帳を 1 本化したり、新規ホストでも S3 sync が通るようにしたり、といった周辺も整えました。
  • コストも試算していて、現行の EC2 6 台常時稼働(8 月実績 $752/月)に対して、9:00 起動 / 23:00 停止を入れるだけでかなり下がる見込みでした。
    • ECS on EC2 や Fargate + Aurora clone 案も比較したうえで、まずは起動停止スケジュールを入れています。
    • 調べていたら EC2 の同世代で intel より amd のほうが高くなっていて、ちょっと驚きました。(以前からそうだったでしょうか?)
  • 停止→起動を入れたら同居している docker コンテナ(MySQL など)が起動しなくなる、E2E が dev の ALB の Google OIDC を通れず staging に到達できない、など、止めてみて初めて出てくる問題もひととおり潰しました。
  • あわせて、誰がどの環境を占有しているかの台帳(インスタンスタグ + hubot の env list)も整備中です。

なお、dev/staging ホストのログが一切ローテートされておらず nginx の error.log が 70.3GiB、ディスク使用率 89%、なんてことも発見しています。

見つかってしまった問題たち

今月も、長く動いているシステムならではの問題がいろいろ出てきました。

  • 月初いきなり、本番の Web サーバーの inode 使用率が 99%(残り 8〜12 日)になっていることに気づきました。ディスクには余裕があるのに、配送されない cron メールが /var/spool/clientmqueue に 82GB 滞留していた、というものです。
    • staging 側でも同様に、2023 年の release を参照し続けている whenever の孤児ブロックから未配送 cron メールが 8.1GB / 208 万通滞留していました。
  • 郵便番号の更新バッチが失敗し続けていて、原因は日本郵便の証明書ローテートに、Web サーバーの 2018 年の CA バンドルが追随できていなかったことでした。Ruby は古くてもよいけど証明書は新しくないとだめ、という話ですね。
  • Debian 11 の EOL で本番/dev の docker build が落ちるようになっていました。master が緑だったのはレイヤキャッシュのおかげだけ、というやつです。
  • GitHub Packages の PAT が失効していて、gem を追加すると本番デプロイが必ず止まる状態になっていました。
  • SendGrid の Event Webhook が WAF の Bot Control に落とされていました。2023 年 7 月から 3 年間です。
  • Redash のクエリ API キーがバッチのコードに直書きされていて、2019 年から git 履歴に残っていたので、ローテーションしました。
  • 本番/staging の known_hosts が古い GitHub のホスト鍵のままで、デプロイのたびに MITM 警告が出ていたので更新しました。
  • 廃番商品ページでレビューの島が無言で空になる、というバグもありました。日付キーのフラグメントキャッシュに asset digest が焼き付いて、古い entry × 新しい vendor の組み合わせになっていた、というなかなか味わい深い原因でした。
  • 使われていない API プロキシのリポジトリをアーカイブしました。

8 月に「動いているように見えていただけ、がいちばん怖い」と書きましたが、9 月はまさにそういうものの連続でした。 特に「3 年間ずっと落ちていた」系は、監視が無いと誰も気づけないので、cron 台帳と失敗検知を先に入れておいてよかったなと思います。

フロントエンド

  • 8 月から進めていた client のフロントエンド要素技術の刷新(Hypernova 撤去 + Vite 移行 + ライブラリ刷新)のエピックを、9 月頭にクローズしました。
  • その残りとして、Node 8 ピン / renovate 除外 / webpack 3 のまま取り残されていた部分を救出しました。
  • 月末は細かいバンドルサイズの改善をやっていて、使っていない proposal の polyfill 注入をやめたり、.babelrc の phantom dependency を解消したり、renovate の client グループを runtime / build-test の 2 本に分けたりしています。

AI との付き合い方

  • ひきつづき Claude Code を複数並列で動かしながら進めています。
  • 一方で、「シェルスクリプトで複雑なもの作りすぎな気がしてきている」というのが今月の自分のつぶやきでした。
    • Claude Code に頼むとシェルスクリプトでもかなり複雑なものがすぐできてしまうので、気づくと運用ツールがシェルで肥大化しているんですよね。どこかで言語を選び直す判断をしたほうがよさそうです。

まとめ

9 月は、8 月に決めた方針に沿って、Next.js 化・コンテナ化・環境整備といったエピックが一斉に実装フェーズに入った月でした。 その一方で、触れば触るほど年季の入った問題が出てくるので、新しいものを作るのと古いものを片付けるのを並行して進めている、という状態です。

おわり