第6周:GusLift 如何实时匹配乘车

发布: (2026年3月15日 GMT+8 21:41)
4 分钟阅读
原文: Dev.to

Source: Dev.to

匹配房间抽象

我们并不运行一个全局池。我们按地点、日期和出发时间进行分区。房间键的形式如下:

Westie:mon:08:00

该字符串成为 Cloudflare Durable Object (DO) 的标识,它是一个实时内存进程,拥有该时段的所有实时状态。所有在周一上午 8 点从 Westie 出发的用户共享同一个房间。10:30 出发?则是完全不同的房间。这使得每个实例都保持小且专注。匹配房间不需要也不关心其他出发窗口的情况。

进入正确的房间

当用户打开应用时,Cloudflare Worker 处理请求。它进行身份验证,解析用户的行程,生成时段键,并将 WebSocket 连接转发到相应的 DO。Worker 是无状态的——纯路由器。所有有趣的状态都保存在它指向的对象中。

DO 追踪的内容

DO 维护四类状态:

  • drivers — 驾驶员 ID → 剩余座位的映射
  • riders_waiting — 请求搭乘的乘客的 FIFO 队列
  • pending_matches — 驾驶员已选但尚未确认的乘客
  • connections — 实时 WebSocket 句柄,每位用户一个

每一次状态变化都会广播给所有已连接的客户端。前端完全镜像 DO 所持有的内容,除此之外没有其他信息。

流程

  1. 驾驶员上线 → 发送 driver_online 并附带座位数 → 在房间中注册,并广播给所有人。
  2. 乘客请求座位 → 发送 rider_request → 加入队列。
  3. 驾驶员挑选乘客 → 该乘客从 riders_waiting 移到 pending_matches,并在其 socket 上收到 match_request
  4. 乘客有 30 秒时间接受。
    • 未响应 → 乘客返回队列。
    • 接受 → 座位数递减,行程写入 Postgres,房间状态对所有人更新。

并发事件——例如两个驾驶员同时选择同一乘客——能够优雅处理,因为 DO 以单线程模型一次执行一条消息,消除了显式锁的需求。

为什么使用 Durable Objects

无服务器平台与 WebSocket 默认配合不佳:无服务器函数是无状态且短暂的,而 WebSocket 需要持久状态。DO 提供了持久的、单线程的进程,拥有跨事件存活的内存状态。对于负载集中在早晨 20 分钟窗口的校园应用来说,房间在需要时启动,空闲时休眠,消除了闲置基础设施和连接交接问题。

剩余工作

尚未解决的开放问题:

  • 驾驶员在匹配被接受后取消。
  • 出发窗口结束后从未被清理的房间。
  • 对 socket 事件的速率限制。

这些挑战在原则上相对直接,只是尚未纳入最初的实现中。

0 浏览
Back to Blog

相关文章

阅读更多 »