外卖系统选型时,技术评审应验证重复订单通知、打印任务登记和结果未知时的处理。本文使用SQLite事务及复合唯一约束,核对同请求重试、载荷冲突、跨商家归属和状态转换,给接单打印演示提供可复现的输入输出。
构造场景中,商家接到已付款订单后登记打印任务。请求号相同且载荷一致时返回原任务,同请求号换订单或设备时拒绝。另一个请求号重复登记同订单、同设备、同用途时,也定位原任务。
示例用商家、请求号作为请求主键,商家、订单、设备和用途共同约束任务唯一。用途区分原始打印和经授权补打,示例只接受original。设备接收、实际出纸和回执恢复属于后续适配。
保存为print_task_revision.py,使用Python 3运行python print_task_revision.py,无第三方依赖。示例在内存SQLite中以单连接顺序执行。商家身份应来自认证上下文,正式服务还需实现授权、参数校验和持久化。
import sqlite3
db = sqlite3.connect(':memory:')
db.executescript('''
CREATE TABLE task (
id INTEGER PRIMARY KEY,
merchant TEXT NOT NULL,
order_id TEXT NOT NULL,
printer TEXT NOT NULL,
purpose TEXT NOT NULL CHECK (purpose = 'original'),
state TEXT NOT NULL DEFAULT 'pending' CHECK (state IN ('pending', 'unknown', 'confirmed')),
UNIQUE (merchant, order_id, printer, purpose)
);
CREATE TABLE request (
merchant TEXT NOT NULL,
request_id TEXT NOT NULL,
order_id TEXT NOT NULL,
printer TEXT NOT NULL,
purpose TEXT NOT NULL,
task_id INTEGER NOT NULL REFERENCES task(id),
PRIMARY KEY (merchant, request_id)
);
PRAGMA foreign_keys = ON;
''')
def register(merchant, request_id, order_id, printer, purpose='original'):
if purpose != 'original':
raise ValueError('purpose')
payload = (order_id, printer, purpose)
with db:
previous = db.execute(
'SELECT order_id, printer, purpose, task_id FROM request '
'WHERE merchant = ? AND request_id = ?',
(merchant, request_id)
).fetchone()
if previous:
if previous[:3] != payload:
raise ValueError('request_conflict')
return previous[3]
db.execute(
'INSERT INTO task(merchant, order_id, printer, purpose) '
'VALUES (?, ?, ?, ?) '
'ON CONFLICT(merchant, order_id, printer, purpose) DO NOTHING',
(merchant, *payload)
)
task_id = db.execute(
'SELECT id FROM task WHERE merchant = ? AND order_id = ? '
'AND printer = ? AND purpose = ?',
(merchant, *payload)
).fetchone()[0]
db.execute('INSERT INTO request VALUES (?, ?, ?, ?, ?, ?)',
(merchant, request_id, *payload, task_id))
return task_id
assert register('M', 'r1', 'O', 'P') == 1
assert register('M', 'r1', 'O', 'P') == 1
assert register('M', 'r2', 'O', 'P') == 1
for order, printer, reason in [('OTHER', 'P', 'request_conflict'),
('O', 'OTHER', 'request_conflict')]:
try:
register('M', 'r1', order, printer)
raise AssertionError('conflict accepted')
except ValueError as error:
assert str(error) == reason
assert db.execute('SELECT count(*) FROM task').fetchone()[0] == 1
assert register('N', 'r1', 'O', 'P') == 2
try:
register('M', 'r3', 'O', 'P', 'reprint')
raise AssertionError('unapproved reprint accepted')
except ValueError as error:
assert str(error) == 'purpose'
assert db.execute('SELECT count(*) FROM request').fetchone()[0] == 3
print('9 assertions passed; tasks=2; request mappings=3')
def transition(task_id, before, after):
allowed = {('pending', 'unknown'), ('pending', 'confirmed'),
('unknown', 'confirmed')}
if (before, after) not in allowed:
raise ValueError('transition')
with db:
return db.execute(
'UPDATE task SET state = ? WHERE id = ? AND state = ?',
(after, task_id, before)
).rowcount
assert transition(1, 'pending', 'unknown') == 1
assert db.execute('SELECT state FROM task WHERE id = 1').fetchone()[0] == 'unknown'
assert transition(1, 'unknown', 'confirmed') == 1
assert transition(1, 'pending', 'unknown') == 0
assert db.execute('SELECT state FROM task WHERE id = 1').fetchone()[0] == 'confirmed'
assert transition(999, 'pending', 'confirmed') == 0
try:
transition(1, 'confirmed', 'pending')
raise AssertionError('terminal rollback accepted')
except ValueError as error:
assert str(error) == 'transition'
print('16 assertions passed in total; task 1 confirmed; stale update=0')商家M用请求r1登记订单O、设备P,得到任务1。重复r1保持任务1,换r2提交相同业务也得到任务1。把r1用于订单OTHER触发request_conflict,原任务和请求映射保持。
本地用例还验证同请求号换设备被拒、另一商家同编号业务得到独立任务,以及未支持的补打用途被拒。加上状态转换,本轮本地共16项构造断言通过,最终输出为16 assertions passed in total; task 1 confirmed; stale update=0。
事务保证本示例的登记和请求映射一起提交。请求表和任务表的唯一约束定义业务边界,不能从内存顺序测试推定生产并发或设备只出一张纸。
任务初始为pending,发送结果不明时条件更新为unknown,设备确认后从pending或unknown进入confirmed。更新同时匹配任务ID与旧状态,确认后迟到的pending更新影响0行,已确认终态拒绝回退。设备确认应携带可核对的任务标识,普通网络超时保留unknown。
评审输入包括相同请求重试、不同请求号重复业务、同请求号载荷冲突与跨商家请求。微订公开产品说明列有商家独立后台,具体设备接口仍按所选版本核验。实际接口还需从认证上下文取得商家身份,核对原订单归属。
任务唯一性与设备副作用分别验收。若设备已打印但响应丢失,需要查询和人工处置,实际补打应有权限、原因和新标识。部署方案还需核数据库持久化、备份、恢复及升级。
示例覆盖任务登记与状态条件更新。生产实现还需验证独立连接并发、进程崩溃恢复、设备查询和鉴权,按业务流程补充退款对账与故障处置。
作者:微订(上海逊柯计算机科技有限公司)。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。