Skip to content

feat: harden repository list against GitHub API failures (#105) - #131

Merged
f0reachARR merged 1 commit into
mainfrom
feat/105-repo-list-lightening
Jun 30, 2026
Merged

feat: harden repository list against GitHub API failures (#105)#131
f0reachARR merged 1 commit into
mainfrom
feat/105-repo-list-lightening

Conversation

@f0reachARR

Copy link
Copy Markdown
Owner

Summary

Issue #105 (レポジトリ一覧画面の軽量化) を満たすため、レポジトリ一覧 API が GitHub API の一時失敗で落ちないようにし、repositories テーブルを webhook + worker で背景同期する仕組みを足した。

変更内容

  • キャッシュ TTL の延長 (crates/api/src/github_access/cached.rs)
    • accessible_repo_ids valid TTL: 10m → 1h
    • stale TTL: 1h → 24h
    • sync throttle: 10m → 30m
    • cleanup ジョブも 24h 残るよう調整(stale fallback の保護)
  • stale fallback を全エラーで有効化
  • github_installation_sync_state テーブル追加 (migrations/20260504000000_add_installation_sync_state.*)
    • webhook_seen_at, last_sync_started_at, last_sync_completed_at, last_sync_status, last_error
    • webhook 鮮度判定のための index
  • Webhook で webhook_seen_at を更新
    • installation / installation_repositories 両方
  • Worker の installation 同期 (crates/worker/src/installation_sync.rs)
    • GitHub App の credential を使い、定期的に list_installationslist_installation_repositoriesrepositories upsert + 削除レポの installation_id クリア
    • webhook が新しい / 直近同期済の installation はスキップ
    • 同期結果を github_installation_sync_state に記録
    • スイープあたり最大件数を環境変数で制限
  • repositories(updated_at DESC, github_repository_id DESC) index
    • 一覧 cursor pagination 向け
  • GitHubAppClientlist_installation_ids / list_installation_repositories を追加
    • 既存 mock は default impl で空 Vec を返すので無改修

スコープ外 / 続編候補

  • 一覧 API から list_accessible_repo_ids を完全に外して repositories テーブル直照会へ寄せる変更は別途。今回は「失敗時に落ちない」「背景で repositories が埋まる」までを担保した。
  • フロント側の 401 リダイレクト導線(GitHub OAuth token 失効時の401ハンドリングを改善する #104 の本丸)

設定 (デフォルト)

INSTALLATION_SYNC_INTERVAL_SECS=1800        # 30分ごと sweep
INSTALLATION_SYNC_STALE_AFTER_SECS=86400    # webhook 24h 来てない installation を sync
INSTALLATION_SYNC_MIN_INTERVAL_SECS=3600    # 同一 installation の最低再同期間隔 1h
INSTALLATION_SYNC_MAX_PER_SWEEP=50          # 1 sweep あたり最大件数

Test plan

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test --workspace(ローカル DB 含む)
  • 新規 unit test: installation_sync::needs_sync (5 ケース)
  • 新規 integration test (crates/worker/tests/installation_sync_test.rs):
    • 未知 installation の sync で repositories が upsert される
    • 直近 webhook の installation はスキップ
    • 失敗時に sync_state.last_sync_status=failed が記録される
    • 削除されたレポは installation_id=0 にクリアされる
  • 新規 webhook test: installation / installation_repositorieswebhook_seen_at を打刻
  • cache TTL 緩和テストの更新(TokenExpired / Upstream は stale fallback、cleanup の 24h grace 維持)

🤖 Generated with Claude Code

Issue #105 fix slice: the repository list endpoint no longer hard-fails
when GitHub momentarily rejects or rate-limits the per-user OAuth call,
and the repositories table is now reconciled in the background regardless
of user activity.

- Extend accessible_repo_ids cache: 10m→1h valid, 1h→24h stale,
  sync throttle 10m→30m. Cleanup job preserves entries 24h past
  expiration so they remain usable as stale fallbacks.
- Cache layer serves stale on any AccessError (TokenExpired / Upstream),
  not only RateLimited.
- Add github_installation_sync_state table tracking
  webhook_seen_at / last_sync_* per installation. Webhook handler
  stamps webhook_seen_at on installation and installation_repositories
  events.
- Worker periodic reconciler (default every 30m) uses GitHub App
  credentials to list installations + their repositories and upserts
  into repositories, skipping installations whose webhook is fresh and
  whose last sync is within the throttle window.
- Add (updated_at DESC, github_repository_id DESC) index on
  repositories for the list endpoint cursor pagination.

Configurable via INSTALLATION_SYNC_INTERVAL_SECS,
INSTALLATION_SYNC_STALE_AFTER_SECS,
INSTALLATION_SYNC_MIN_INTERVAL_SECS,
INSTALLATION_SYNC_MAX_PER_SWEEP.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@f0reachARR
f0reachARR merged commit 2d664a5 into main Jun 30, 2026
3 checks passed
@f0reachARR
f0reachARR deleted the feat/105-repo-list-lightening branch June 30, 2026 14:43
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