perf(worker): 「我的订单」缓存改为事件驱动失效,TTL 2s/5s → 30s
这是当前最大瓶颈的根治:打手端三件套(列表/计数/概览)占全库约 75% 缓冲读, 单查询成本是 O(打手单量) 的固有成本(重打手 8,586 单逐行探测), 索引层面已无可抠,只能把"计算次数"和"访问次数"解耦。 原先 TTL 只有 2s/5s,是因为文档担心"再长会让分页总数滞后"。 但该数据只在该打手自己的工单流转时才变,而项目已有 realtime 快照广播 精确感知每次流转——把同一事件流接到缓存失效上,长 TTL 与新鲜度可以兼得, 正确性反而优于固定 5s(那同样存在滞后窗口)。 - WorkerListCache 新增 evictByPrefix:按键前缀整体逐出; - 缓存实例抽到中立模块 worker-my-order-cache.ts:realtime 需要引用失效入口, 而 my-order-service 已 import realtime,实例放任何一方都会循环依赖; - 缓存键统一为 ["w",workerId,scope,detail],前缀失效不会误伤其它打手; - 失效挂在 publishWorkOrderSnapshots:那里恰好已有工单 + 全部拼单人, 受影响集合取 当前指派 + 历史保留 + 全部拼单人 + 调用方指定, 21 处工单写入路径(含取消申请/反馈处理)都会经过; 工单已删除的分支同样失效,避免打手继续看到已删的单。 最坏情况(漏失效)是打手最多 30s 看到旧状态,与原 5s TTL 的滞后窗口同性质。 守卫测试锁定:失效入口存在、键前缀格式、受影响集合三要素齐全。
This commit is contained in:
@@ -29,6 +29,7 @@ import {
|
||||
mapWorkerUser,
|
||||
resolveWorkerPermissions,
|
||||
} from '../worker-platform/mappers.js'
|
||||
import { invalidateWorkerMyOrderCaches } from '../worker-platform/worker-my-order-cache.js'
|
||||
|
||||
export type RealtimeEventType =
|
||||
| 'admin_notification.changed'
|
||||
@@ -249,6 +250,9 @@ async function publishWorkOrderSnapshots(input: {
|
||||
const workOrderId = Math.max(0, Number(input.workOrderId) || 0)
|
||||
const workOrder = await getWorkOrderById(workOrderId)
|
||||
if (!workOrder) {
|
||||
// 工单已不存在(删除):调用方传入的打手集合仍需失效缓存,
|
||||
// 否则他们的「我的订单」会继续展示已删除的单。
|
||||
invalidateWorkerMyOrderCaches(input.workerIds || [])
|
||||
publishRealtimeEvent({
|
||||
type: 'work_order.changed',
|
||||
entityId: workOrderId,
|
||||
@@ -262,6 +266,18 @@ async function publishWorkOrderSnapshots(input: {
|
||||
|
||||
const pendingUnfreezeByOrderId = await sumPendingUnfreezeByOrderIds([workOrderId])
|
||||
const shares = await listWorkOrderShares(workOrderId)
|
||||
|
||||
// 事件驱动缓存失效:这里已经拿到的工单与拼单快照恰好给出完整的受影响打手集合
|
||||
// (当前指派 + 历史保留 + 全部拼单人 + 调用方显式指定的)。
|
||||
// 先失效再广播,保证打手端随后的拉取一定看到新数据;这也是「我的订单」缓存
|
||||
// 能放心用 30s 长 TTL 的前提(见 worker-my-order-cache.ts)。
|
||||
invalidateWorkerMyOrderCaches([
|
||||
...(input.workerIds || []),
|
||||
workOrder.assigned_worker_id,
|
||||
workOrder.last_assigned_worker_id,
|
||||
...shares.map((share) => share.worker_id),
|
||||
])
|
||||
|
||||
const joinedQuantity = shares
|
||||
.filter((share) => share.status !== 'cancelled')
|
||||
.reduce((sum, share) => sum + Number(share.quantity || 0), 0)
|
||||
|
||||
Reference in New Issue
Block a user