diff --git a/server-rs/crates/spacetime-module/src/external_generation.rs b/server-rs/crates/spacetime-module/src/external_generation.rs index 91f0758ba..8aa594511 100644 --- a/server-rs/crates/spacetime-module/src/external_generation.rs +++ b/server-rs/crates/spacetime-module/src/external_generation.rs @@ -885,6 +885,13 @@ fn claim_external_generation_jobs_tx( .then_with(|| left.job_id.cmp(&right.job_id)) }); + // TODO(并发认领公平性): `take(limit)` 只检查按 `available_at / created_at` 排序的前 `limit` 行, + // 而 `limit` 就是 worker 空闲槽数(api-server 传 `available`,池子默认 2 / release 8),被并发上限 + // 拦下或被 lease 耗尽终结的行只 `continue`,却已吃掉一个检查名额。若队头若干行都属已饱和账号, + // 本轮 `claimed` 可能为空,后面其它账号的可认领任务看不到 —— 跨账号队头阻塞;负载越高 `limit` + // 越小(7/8 worker 占用时 `limit = 1`)越容易触发。 + // 修法(未决,改前需确认单事务写集上界):遍历全部候选,成功认领一行才计数,`claimed.len() >= limit` + // 才 break,被跳过 / 终结的行不占名额,仍是全局 FIFO;若要「不同账号平均穿插」则需另做按账号轮转。 let mut claimed = Vec::new(); let mut concurrency = ExternalGenerationOwnerConcurrencyCache::default(); for mut row in candidates.into_iter().take(limit) {