Skip to content

perf(web): 起動時に一覧の取得をセッションの確認と並べて始める - #213

Merged
rytkhs merged 5 commits into
developfrom
perf/prefetch-recipe-list
Sep 26, 2026
Merged

rytkhs merged 5 commits into
developfrom
perf/prefetch-recipe-list

Conversation

@rytkhs

@rytkhs rytkhs commented Sep 26, 2026 •

Copy link
Copy Markdown
Owner

概要

起動時、一覧(/recipes)の取得を get-session の完了を待たずに始めます。画面の描画はこれまでどおり session の確定を待ちます(ADR 0011)。ブラウザと Worker の往復が直列に 1 回減ります。

Closes #202

背景

ProtectedLayout は session が確定するまで <Outlet /> を描かず、一覧の useInfiniteQuery はその中にあるため、GET /api/recipes は get-session の応答のあとに始まっていました。

#202 の起票後、Worker を aws:ap-southeast-1 に置いた(#203)ことで DB 1 段の待ちは小さくなり(#205 の計測で cache 切れと有効の差は 6〜20ms)、起動時の待ちの大半はブラウザと Worker の往復(日本から cookie なしの get-session で TLS 確立後 約 160〜190ms)が 2 回直列に並ぶことによるものになっています。

先に取っても、cache が切れていれば /api/recipes は自分で session を 2 段引くので、クリティカルパス上の DB の段数は変わりません。縮むのは往復 1 回分と、その間の描画です。Worker の配置を日本側に戻しても遅くはならず、短縮幅が小さくなるだけです。

変更

  • 一覧の取得設定(key、queryFn、staleTime 5 分など)を recipeListQueryOptions にまとめ、画面と loader で共有する
  • router の context で queryClient を渡し、router は main.tsx で作る
  • /recipes の loader で一覧の最初のページを prefetchInfiniteQuery する。Promise は返さない(返すと router が完了を待つ)
    • 先に取るのは起動の入口の条件(検索語・タグ・「タグなし」の指定なし)だけ。起動時の一覧は常にこの条件で(並び順はメモリにだけ持つ)、アプリを開いた後の絞り込みは画面が自分で取るのと同時になり縮まないため。条件の組み立てを loader と画面で二重に持たずに済む
  • TanStack Query の既定の再試行で 401 を繰り返さない。401 は取り直しても変わらず、session の回復は viewer の経路が担う(ADR 0011)。これまではタグ一覧や取り込み状況なども 401 を 3 回再試行していた
  • isUnauthorizedError を lib/api.ts に置き、protected-access.ts の同じ判定を置き換える
  • ADR 0012: 「起動の入口の最初の取得だけを、session の確認と並べて始める」という決め方として記録。通知から開く詳細や共有から開く取り込みの画面は、今は先に取らない
  • ADR 0011: 既定の再試行が 401 を対象にしないことを記録

未ログインで /recipes を開くと、/api/recipes が 401 を 1 回返してからログインへ移ります。失敗は一覧のキャッシュに残りますが、ログイン後に画面が mount すると取り直します(retryOnMount)。

起動時は get-session と /api/recipes がそれぞれ DB で session を引き、それぞれが cookie cache を配ります(session の照会が 1 本増える)。

計測

ローカルのモック(API 遅延 1000ms、/recipes を開き直した回)で、変更前のコミットと比較。

get-session /api/recipes の開始 一覧のリンクが出るまで
変更前 1551→2574ms 2605ms 約 3.86s
変更後 1572→2599ms 1570ms 約 2.88s

本番での所要時間は未計測です。現在の配置での見込みは、往復 1 回分の約 170ms です。

検証

  • pnpm typecheck
  • pnpm lint
  • pnpm test(全パッケージ)
  • 追加したテスト(router.test.tsx): get-session の応答を止めた状態で一覧の取得が 1 回出て、session の確定後にその結果を取り直さずに描画する。loader の先取りを外すと失敗することを確認済み
  • git diff --check

/recipes の loader で一覧の最初のページを先に取る。画面の描画はこれまで
どおり session の確定を待つ。API は requireAuth で自ら session を確かめる
ので、未ログインなら 401 が返るだけで画面には出ない。

- 一覧の取得設定を recipeListQueryOptions にまとめ、画面と loader で共有する
- router の context で queryClient を渡し、router は main.tsx で作る
- URL にタグの指定があるときは先に取らない(消えたタグの id を外してから取るため)
- 先に取るときは 401 を再試行しない

Refs #202
起動時の一覧は常に絞り込みなしで、絞り込んだ一覧は画面が自分で取るのと
同時になるので、先に取っても縮まない。条件の組み立てを loader と画面で
二重に持たないよう、先取りを絞り込みなしに限る。

Refs #202
401 は取り直しても変わらず、session の回復は viewer の経路が担う(ADR 0011)。
一覧の先取りだけに置いていた 401 の除外を、既定の再試行に移す。

Refs #202
@rytkhs
rytkhs merged commit 66841aa into develop Sep 26, 2026
1 check passed
@rytkhs
rytkhs deleted the perf/prefetch-recipe-list branch September 26, 2026 13:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant