diff --git a/server-rs/crates/api-server/src/game_play_counter.rs b/server-rs/crates/api-server/src/game_play_counter.rs index 60f131c7d..d8fb7c598 100644 --- a/server-rs/crates/api-server/src/game_play_counter.rs +++ b/server-rs/crates/api-server/src/game_play_counter.rs @@ -157,13 +157,17 @@ impl GamePlayCounter { return None; } state.last_flush_at = now; - Some(drain_pending(&mut state.pending)) + let deltas = drain_pending(&mut state.pending); + drop(state); + Some(sort_deltas(deltas)) } /// 无条件取走全部增量,供关停 flush 使用。 pub fn take_pending(&self) -> Vec { let mut state = self.lock(); - drain_pending(&mut state.pending) + let deltas = drain_pending(&mut state.pending); + drop(state); + sort_deltas(deltas) } /// 写库失败时把增量放回,等待下一次 flush。 @@ -207,11 +211,14 @@ impl GamePlayCounter { } fn drain_pending(pending: &mut HashMap) -> Vec { - let mut deltas = pending + pending .drain() .filter_map(|(game_id, delta)| (delta > 0).then_some(GamePlayCountDelta { game_id, delta })) - .collect::>(); - // 稳定批次顺序,便于测试与日志比对。 + .collect() +} + +/// 稳定批次顺序,便于测试与日志比对;调用方已释放计数锁,排序不阻塞并发 `record`。 +fn sort_deltas(mut deltas: Vec) -> Vec { deltas.sort_by(|left, right| left.game_id.cmp(&right.game_id)); deltas }