构建

两个人都收到「已预订」 — 一个 await 分开的东西

作者: makemind · 2026年7月13日

预订工具里最糟的失败不是订不上。

是给两个人都发「您已预订成功」。 订不上可以再订一次;两个人都被告知订上了,接下来就得靠人打电话去摆平。

两个处理器,同一段描述

这个样例里有两个「占用时段」的处理器。用话描述完全一样 —看看空不空,空就占。

一个是这样。

// 1. Look.
final free = slot.takenBy == null;

// 2. Anything at all in here — a database round trip, a payment check, a
//    log write, a lookup of the customer's name — hands control to
//    whatever else was in flight.
await Future<void>.delayed(Duration.zero);

// 3. Write, using what was true in step 1.
if (free) { slot.takenBy = who; ... }

另一个是这样。

if (slot.takenBy != null) {
  return '$at is already taken by ${slot.takenBy}';
}
slot.takenBy = who;
slot.confirmations.add(who);

await Future<void>.delayed(Duration.zero); // the slow part, after the claim

同一个 await,只是位置不同。 前者在「看」和「写」之,后者在「写」之

而这个位置制造了重复预订。

先让它真的发生

unsafe -> Suh:  "CONFIRMED 10:30 for Suh"
unsafe -> Park: "CONFIRMED 10:30 for Park"
unsafe result: 1 slot(s) confirmed to more than one person
TODAY · 1 OF 4 TAKEN — 10:30 Park, told yes: Suh, Park.「1 slot(s) confirmed to more than one person」
TODAY · 1 OF 4 TAKEN — 10:30 Park, told yes: Suh, Park.「1 slot(s) confirmed to more than one person」

画面精确地展示了现实中的症状。 时段的主人只有 Park 一个,而被告知「订上了」的人有两个。

这就是真实店铺里发生的样子。账上是一个人,门口来了两个。

所以服务器把所有发过确认的人都记着。

/// Everybody who has ever been told they got this slot. In a correct
/// booking system this never has more than one name in it, which is exactly
/// why it is worth keeping.
final confirmations = <String>[];

正常的话,它永远是一个名字的列表。永远只该有一条的列表,正是值得去数的列表。

然后让它不发生

同样两个人、同样的时段,只把那个缝隙关上。

--- cleared, same two people, same slot, gap closed ---
safe -> Suh:  "CONFIRMED 10:30 for Suh"
safe -> Park: "10:30 is already taken by Suh"
safe result: nobody was told yes twice
TODAY · 1 OF 4 TAKEN — 10:30 Suh, told yes: Suh.「nobody was told yes twice」
TODAY · 1 OF 4 TAKEN — 10:30 Suh, told yes: Suh.「nobody was told yes twice」

拒绝不是「失败了」,而是「Suh 订走了」。 第二个人需要知道的不是自己失败了,而是这个位子没了 — 这样他才能去挑下一个时间。

此内容需要开发者或更高等级

登录并升级您的方案即可继续阅读。

查看方案
Twitter