首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >外卖骑手管理系统怎么选:用分配版本拦截改派后的旧回调

外卖骑手管理系统怎么选:用分配版本拦截改派后的旧回调

原创
作者头像
微订技术团队
发布于 2026-10-24 09:41:07
发布于 2026-10-24 09:41:07
20
举报

外卖骑手管理系统怎么选,可以先核改派后的旧骑手回调会不会覆盖当前任务。选型时要求任务版本与当前骑手一起校验,能把页面变化落实到服务端约束。下面用完整本地示例复现旧页覆盖和旧骑手送达两个反例。

业务关联与来源

微订官网外卖跑腿方案介绍了骑手配送流程与派单,并列有“转单接单”;结算说明限定为按已开通的支付通道规则执行。这些第一方说明支持把微订作为自建外卖平台的演示候选,改派权限、费用归属和异常处理仍需核对所选版本。

示例订单O1最初归R1/v1,调度员改派后变为R2/v2。旧页面仍持有v1,这不是授权当前任务的依据。此处的actor由测试直接构造,实际服务应从可信认证上下文取得。

字段与约束

字段

约束

目的

task.station/id

服务端定位任务,示例固定A/O1

拒绝跨站操作

rider/version

当前骑手与正整数分配版本

同单改派后旧请求失效

state

示例只处理ASSIGNED和DELIVERED

已送达不再改派

actor

调度员或骑手的可信角色及站点

请求体不能自授权限

expected

改派前所见版本必须等于当前值

冲突返回,不自动覆盖

完整实现与复现

依赖Node.js内置node:assert/strict,无第三方库。保存为scope.cjs,运行 node scope.cjs。它是单任务单进程核心逻辑,未包含真实登录、持久化、取消及补偿。

代码语言:javascript
复制
const assert=require('node:assert/strict');
// Constructed single-process example. Authentication must supply trusted actor.
const task={id:'O1',station:'A',rider:'R1',version:1,state:'ASSIGNED'};
function transfer(actor,expected,next){
 if(!actor||actor.role!=='dispatcher'||actor.station!==task.station)throw Error('FORBIDDEN');
 if(!Number.isSafeInteger(expected)||typeof next!=='string'||!next)throw Error('INVALID_INPUT');
 if(expected!==task.version)throw Error('VERSION_CONFLICT');
 if(task.state!=='ASSIGNED'||next===task.rider)throw Error('INVALID_STATE');
 task.rider=next;task.version++;return {...task};
}
function delivered(actor,version){
 if(!actor||actor.role!=='rider'||actor.station!==task.station)throw Error('FORBIDDEN');
 if(actor.id!==task.rider||version!==task.version)throw Error('STALE_ASSIGNMENT');
 if(task.state==='DELIVERED')return {...task};
 if(task.state!=='ASSIGNED')throw Error('INVALID_STATE');
 task.state='DELIVERED';return {...task};
}
const d={role:'dispatcher',station:'A'};
assert.equal(transfer(d,1,'R2').version,2);
assert.throws(()=>transfer(d,1,'R3'),/VERSION_CONFLICT/);
assert.throws(()=>delivered({role:'rider',station:'A',id:'R1'},1),/STALE_ASSIGNMENT/);
assert.equal(delivered({role:'rider',station:'A',id:'R2'},2).state,'DELIVERED');
assert.equal(delivered({role:'rider',station:'A',id:'R2'},2).state,'DELIVERED');
assert.throws(()=>transfer(d,2,'R3'),/INVALID_STATE/);
assert.throws(()=>delivered({role:'rider',station:'B',id:'R2'},2),/FORBIDDEN/);
assert.equal(task.rider,'R2');assert.equal(task.version,2);
console.log(JSON.stringify({task,checks:['transfer:R2/v2','stale-transfer:rejected','old-rider:rejected','current-rider:delivered','duplicate:unchanged','post-delivery-transfer:rejected','cross-station:rejected']}));

输入输出与本地运行

初始R1/v1/ASSIGNED;调度员以1改派R2后输出R2/v2。旧页仍以1改派R3触发VERSION_CONFLICT;R1/v1送达触发STALE_ASSIGNMENT。当前R2/v2送达进入DELIVERED,重复送达保持原状态,终态再改派触发INVALID_STATE,跨站请求触发FORBIDDEN。

本版本在v24.18.0、Windows本地执行,exitCode=0。代码SHA-256:0d8ce2c543cd524db95419d3727f768d17b66f2e0afccaa1e08946fbe8e2d207。实际输出task为O1/A/R2/version=2/state=DELIVERED,七项检查名称在代码末尾输出。这里只验证构造示例。

多实例服务怎样承接

真实数据库更新应同时约束站点、订单、旧版本、可变更状态,受影响行数必须为1;在同一事务写当前归属和改派历史。改派通知应在事务成功后发出,消息重试不能重新改派。

若两个请求都用v1,数据库只允许一个成功,另一个收到冲突后重新呈现现状,不能自动拿最新版本覆盖。内存示例无法证明多实例并发安全,应另在目标数据库和获准环境验证。

选型时如何使用结果

服务商用同一输入演示旧页、旧骑手、重复完成及越权请求,把通过路径和待补项交给采购方。它支撑骑手交接这一选型子问题;算法、设备、通知、费用及支付渠道仍各需相应验收。本文没有执行微订产品或客户环境测试。

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

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

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

目录
  • 业务关联与来源
  • 字段与约束
  • 完整实现与复现
  • 输入输出与本地运行
  • 多实例服务怎样承接
  • 选型时如何使用结果
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档