目的
孤児削除で保留(withheld)になったページが削除枠を消費するため、その後ろに並ぶ「本当に消えたページ」が処理されないまま滞留しうる。枠の勘定を見直す。
前提(#196 で導入された挙動)
reap ループは orphans.slice(0, deleteBudget) を回し、存在確認が gone 以外だった候補は continue で抜ける。したがって保留も 1 枠を消費する。
孤児リストは compareSlugs で安定ソートされているため、_pages の列挙が恒常的に短い状態が続く間、同じ候補が毎 run 先頭 5 件を占める。その後ろに実際に削除されたページが並んでいると、列挙が回復するまで処理されない。
これは #187 が禁じた「列挙が正しく縮んだ場合に永久に削除できなくなる」形ではない(正しく縮んだ場合は保留が発生しない)。また #196 以前はその 5 件を削除していたので退行でもない。滞留するのは削除であって、索引の正しさは損なわれない。
制約
方針(採用)
削除枠と probe 枠を分ける(検討 3 案のうち 1 番目)。保留は probe 枠だけを消費し、削除枠は実削除にのみ使われる。
MAX_WIKI_REAP_PROBES_PER_REPO_PER_RUN を新設する。値は 15(削除枠 5 の 3 倍)
- reap ループを
orphans.slice(0, deleteBudget) ではなく orphans 全体に対して回し、removed >= deleteBudget || probes >= probeBudget で break する
probes は probeWikiPageAlive を呼んだ回数で数える
予算の根拠: probe は 1 候補あたり最大 WIKI_EXTENSIONS.length = 2 subrequest(probeWikiPageAlive の doc comment)。probe 枠 15 で上限 30、実削除の fan-out が 5 × 約 4 = 20。walk 側の fetch 予算 20 とは別枠で、invocation あたり 1000 に対して余裕がある。
orphansDeferred の意味を合わせること。現在は orphans.length - deleteBudget で計算しているが、枠を分けた後は「この run で到達しなかった候補数」= orphans.length - 処理した候補数 でなければログと実態がずれる。
採らなかった案と理由:
受け入れ条件
- 保留候補が先頭を占めた状態で、後ろに並ぶ「実際に削除されたページ」が同一 run で削除されることがテストで固定されている
- per-run の probe 回数に上限があり、テストで固定されている
orphansWithheld とログの内容が従来どおり
orphansDeferred が「この run で到達しなかった候補数」を表すことがテストで固定されている
想定変更箇所
src/poller.ts(reap ループの枠勘定)
src/poller-wiki.test.ts
- 対応する docs
目的
孤児削除で保留(withheld)になったページが削除枠を消費するため、その後ろに並ぶ「本当に消えたページ」が処理されないまま滞留しうる。枠の勘定を見直す。
前提(#196 で導入された挙動)
reap ループは
orphans.slice(0, deleteBudget)を回し、存在確認がgone以外だった候補はcontinueで抜ける。したがって保留も 1 枠を消費する。孤児リストは
compareSlugsで安定ソートされているため、_pagesの列挙が恒常的に短い状態が続く間、同じ候補が毎 run 先頭 5 件を占める。その後ろに実際に削除されたページが並んでいると、列挙が回復するまで処理されない。これは #187 が禁じた「列挙が正しく縮んだ場合に永久に削除できなくなる」形ではない(正しく縮んだ場合は保留が発生しない)。また #196 以前はその 5 件を削除していたので退行でもない。滞留するのは削除であって、索引の正しさは損なわれない。
制約
gone以外は削除しない、という spec(wiki): orphan reap has no guard against a partially enumerated _pages index #187 の判定は変えないことorphansWithheldとログ)を落とさないこと方針(採用)
削除枠と probe 枠を分ける(検討 3 案のうち 1 番目)。保留は probe 枠だけを消費し、削除枠は実削除にのみ使われる。
MAX_WIKI_REAP_PROBES_PER_REPO_PER_RUNを新設する。値は 15(削除枠 5 の 3 倍)orphans.slice(0, deleteBudget)ではなくorphans全体に対して回し、removed >= deleteBudget || probes >= probeBudgetで break するprobesはprobeWikiPageAliveを呼んだ回数で数える予算の根拠: probe は 1 候補あたり最大
WIKI_EXTENSIONS.length= 2 subrequest(probeWikiPageAliveの doc comment)。probe 枠 15 で上限 30、実削除の fan-out が 5 × 約 4 = 20。walk 側の fetch 予算 20 とは別枠で、invocation あたり 1000 に対して余裕がある。orphansDeferredの意味を合わせること。現在はorphans.length - deleteBudgetで計算しているが、枠を分けた後は「この run で到達しなかった候補数」=orphans.length - 処理した候補数でなければログと実態がずれる。採らなかった案と理由:
受け入れ条件
orphansWithheldとログの内容が従来どおりorphansDeferredが「この run で到達しなかった候補数」を表すことがテストで固定されている想定変更箇所
src/poller.ts(reap ループの枠勘定)src/poller-wiki.test.ts