余额为什么会被扣两次?交易系统里的并发、幂等与账本

用户点了一次下单,服务端却可能处理两次。更棘手的是:接口超时了,钱到底有没有扣?

在虚拟资产交易系统里,余额扣减看起来只是一条 UPDATE。真正的难点,是让重试、并发下单、部分成交和撤单发生之后,资金仍然能对得上。

我理解这类系统时,会先暂时放下微服务拆分图,追问三件事:哪一笔业务改变了余额?这次改变能否重复执行?进程在中间退出之后,下一次请求凭什么知道结果?

支付成功了,订单却没变:从 RabbitMQ 重试到 Outbox

支付渠道说成功,用户却看见“待支付”。这时最容易做错的一件事,就是让用户再付一次。

问题可能出在回调丢失,也可能是数据库已经更新、后续消息却没有发出去。接入 MQ 只是把工作移到了另一个进程,消息的可靠性仍然需要从业务事务开始设计。

这篇文章沿着“支付结果进入系统 → 订单更新 → 权益发放”的路径,拆开每个可能留下半成品的地方。

订单列表越翻越慢,先别急着分库分表

第一页很快,第两千页却卡住;数据库 CPU 不高,接口 P99 仍然上升。这样的慢,往往不是“机器不够用”这么简单。

订单系统同时要服务用户最近订单、商家待处理列表和运营跨店检索。把这些访问方式塞进一个万能查询,再加几个单列索引,数据增长之后很容易暴露问题。

我更愿意按“请求耗时在哪里 → 数据库读取了多少 → 返回内容是否必要”的顺序处理,再决定要不要引入缓存和分片。

MQTT 消息收到了,设备为什么还没执行?

平台显示“启动成功”,现场设备却没有动作;用户重试一次,设备又在稍后连续执行。

远程设备控制最容易产生误解的地方,是把传输层成功当成了业务成功。MQTT 帮助传递消息,但真正的执行结果,需要设备、业务服务与界面共同表达。

从充电桩到教学机房的批量设备管理,这个问题有一个共同点:网络会断,回执会晚,设备可能在执行动作后立刻重启。

AIGC 平台做完页面之后:交付版本、视频访问与可回滚发布

一个创作平台最难交付的部分,往往不在首页。

创作者上传了新版本,客户却还在审核旧文件;付款后课程能播放,链接转发出去也能播放;应用回滚成功,数据库字段却已经无法兼容。功能逐项可用,并不自动等于整套业务可以可靠运行。

在 AIGC 制作、创作者协作和在线教学这类系统中,我会把交付理解为四件事:业务状态能解释,文件版本能追溯,权限在服务端成立,发布失败能恢复。

序行 Agent|从工具调用到商业交付的开发复盘

让 Agent 操作真实业务系统,最难的一步,是知道它究竟有没有做成。

序行 Agent 是我独立开发的私人闭源商业项目:一个面向跨平台业务协作的 Windows 智能体工作台。用户用自然语言提出任务,Agent 在实际业务页面中查询、整理资料、导出文件,并准备跨系统客户与订单录入。

我负责从产品交互、Agent 运行时与工具桥接,到 Rust 业务执行器、浏览器集成和桌面打包的完整开发。这篇文章重点记录其中的 Agent 工程:如何让模型选对工具、依据真实页面行动,在长任务中保留事实,并把涉及业务写入的动作交给可核验的执行流程。

独立开发 · 私人商业项目 · Agent Runtime · Tool Calling · Rust · CDP