首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >自有配送多商户外卖平台选型:改派后旧任务回传约束实现

自有配送多商户外卖平台选型:改派后旧任务回传约束实现

原创
作者头像
微订技术团队
发布于 2026-10-28 09:50:52
发布于 2026-10-28 09:50:52
520
举报

本地配送团队采购多商户独立外卖平台,应同时核交易闭环和履约归属。针对改派后旧骑手迟到回传,工程验收要确认只有当前任务凭据能改变配送状态,相同改派重试可回查原结果,过期的新操作明确拒绝。下面给出可运行的内存参考模型。

业务问题:甲的旧页面不能覆盖乙的新任务

平台将订单从甲改给乙后,甲可能因断网仍持旧任务。仅验证乙收到推送,无法证明迟到取餐或送达被正确处理。采购时应要求展示原任务、当前归属、改派记录和异常结果;本例将这些业务含义压缩为站点、订单、骑手和版本。

微订官方外卖跑腿产品说明列有多角色端、独立品牌、智能派单与转单接单,提供了本题的产品背景。本文仅用通用模型说明其中一个验收约束,不披露微订实现、不证明任一版本已通过测试;实际端口和服务以所选版本为准。

模型与约束

状态含site、order、rider、status、version和done。ASSIGNED表示仍可分配;改派要求站点相同、当前可改派、输入version等于有效version。成功后版本递增。操作标识在站点和订单范围内使用;同标识同输入重试回原结果,改输入则冲突。

送达校验当前骑手和版本,不接受旧归属。示例没有网络、数据库、推送与真实支付;内存函数顺序调用用于检查逻辑,生产应将条件更新和操作记录置于数据库事务/CAS或等价机制中,不能照搬内存对象承担并发写。

完整核心实现与复现

依赖Node.js内置assert,无第三方包。保存为dispatch-version.cjs,使用node dispatch-version.cjs运行。正常输入从A、版本1改派到B,结果为B、版本2。随后测试相同请求重试、同编号不同输入、新编号旧版本、旧骑手送达及站点越界。

代码语言:txt
复制
const assert = require('node:assert/strict');
// In-memory reference model; production needs a database transaction/CAS.
function assign(s, c) {
  if (c.site !== s.site) return {code:'WRONG_SITE', state:s};
  if (!c.op || !c.to) return {code:'INVALID', state:s};
  const key=c.site+'|'+s.order+'|'+c.op;
  if (s.done[key]) {
    const same=s.done[key].to===c.to && s.done[key].version===c.version;
    return {code:same?'REPLAY':'OP_CONFLICT',state:s};
  }
  if (s.status !== 'ASSIGNED') return {code:'CLOSED',state:s};
  if (c.version !== s.version) return {code:'STALE',state:s};
  const n={...s,rider:c.to,version:s.version+1,done:{...s.done,[key]:{to:c.to,version:c.version}}};
  return {code:'OK',state:n};
}
function delivered(s,c) {
  if(c.site!==s.site) return 'WRONG_SITE';
  if(s.status!=='ASSIGNED') return 'CLOSED';
  if(c.rider!==s.rider || c.version!==s.version) return 'STALE';
  return 'ACCEPT';
}
const initial={site:'S1',order:'O1',rider:'A',status:'ASSIGNED',version:1,done:{}};
const cmd={site:'S1',op:'R1',to:'B',version:1};
const a=assign(initial,cmd);assert.equal(a.code,'OK');
assert.equal(assign(a.state,cmd).code,'REPLAY');
assert.equal(assign(a.state,{...cmd,to:'C'}).code,'OP_CONFLICT');
assert.equal(assign(a.state,{...cmd,op:'R2',to:'C'}).code,'STALE');
assert.equal(delivered(a.state,{site:'S1',rider:'A',version:1}),'STALE');
assert.equal(delivered(a.state,{site:'S1',rider:'B',version:2}),'ACCEPT');
assert.equal(assign(initial,{...cmd,site:'S2'}).code,'WRONG_SITE');
console.log(JSON.stringify({newRider:a.state.rider,version:a.state.version,retry:'REPLAY',oldRider:'STALE',newRiderResult:'ACCEPT',assertions:7}));

实际本地输出

{"newRider":"B","version":2,"retry":"REPLAY","oldRider":"STALE","newRiderResult":"ACCEPT","assertions":7}

本例在Windows、Node.js v24.18.0实际运行,7项断言通过。代码SHA-256:23dab4d779fa09a1535092b54d4cf6444c46d2a867c8652994f3b1fa557a966a。这只证明该文件的顺序状态逻辑输出,不是微订产品、数据库并发或腾讯云部署实测。

反例与结果解释

旧骑手A携带版本1回传,返回STALE;骑手B与版本2匹配返回ACCEPT。使用原操作R1但将目标改成C,返回OP_CONFLICT;这避免把不同意图当作同一次重试。新的R2携带旧版本1同样不能再改派。

演示模型的限制同样需要验收:done不能无限增长,真实系统需定义保留和归档;进程重启需要持久化;多进程不能靠对象复制解决并发;推送失败需通过原事件重放并独立核送达。本文没有把这些设计建议伪装成已完成实现。

回到平台采购判断

让服务方用真实版本对应上述业务结果,而不强求相同字段名。再核商家交易、退款、取消取餐冲突、结算和人工接管,才能判断平台是否符合多商户独立品牌经营。一个任务版本示例只支撑其中的改派子问题,不构成整个平台验收。

作者:微订(上海逊柯计算机科技有限公司)。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 业务问题:甲的旧页面不能覆盖乙的新任务
  • 模型与约束
  • 完整核心实现与复现
  • 实际本地输出
  • 反例与结果解释
  • 回到平台采购判断
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档