D-20260802-06|active + reserved 原子容量¶
背景與驅動力¶
SpectatorServer 原先先以已完成登記的 spectatorCount 檢查容量,再非同步開通道。兩個請求可同時看見最後一格仍空並一起放行;maxPendingOpens 只限制半開總量,不能代表房間容量。
考慮過的選項¶
- 只降低
maxPendingOpens:仍無法把半開請求綁到房間容量。 - 開通道完成後再踢超額者:會建立不應存在的 transport,且結果受完成順序影響。
- admission 前取得一次性容量 reservation(採納):成功轉 active,所有失敗路徑釋放。
決定¶
- 唯一放行條件為
active + reserved < maxSpectators;檢查與保留必須是同一個同步原子操作。 - reservation 在
openChannel前取得。成功後 commit 成 active;開通道失敗、拒絕或 dispose 必須 release;當前 active channel close 才 deactivate。 - 相同 PeerId 重連替換既有 active session,不新增名額;同一 PeerId 的兩個 concurrent reservations 不得同時存在。
maxPendingOpens保留為獨立 DoS 背壓,先後順序不得讓它取代房間容量。- generic
CapacityReservations<Key>放在 matchmaking domain,後續 participant Quick Match reservation 必須重用同一 primitive,而不是另寫一套計數。
後果與影響¶
併發加入不能超過房主設定上限,半開失敗也不會永久吃掉名額;同身分重連仍可在滿房時替換。代價是所有 async admission 路徑都必須明確 settle reservation,漏掉任何 release 都會 fail-closed 佔住容量。