异步方案的最小闭环

异步方案的最小闭环

封面信息图

做异步服务的第一版时,我更愿意先跑通一个请求,而不是立刻加入消息队列、重试框架和多级并发控制。组件越多,失败后越难判断是谁没有返回。最小闭环只需要明确输入、调用一个异步依赖、设置等待上限,并把成功或失败如实交给调用方。

let reply = tokio::time::timeout(Duration::from_secs(1), fetch()).await??;

示例里的一秒只为了让测试容易触发,不是生产建议。真正的超时时间要从用户能够等待多久、上游预算和依赖响应分布倒推。若整个请求只允许等待一段时间,内部调用就不能各自拿走完整预算,还要给序列化、返回响应和必要的清理留出空间。

把错误拆开,别都变成“请求失败”

timeout 外层和 fetch() 内层可能产生不同错误:前者说明等待超过约定,后者可能是连接失败、对方拒绝或响应格式不对。接口应保留足够的错误类别,让上层知道能否重试、是否要提示用户修改输入。底层堆栈可以留在受控日志中,响应里只返回稳定且不泄露内部地址的信息。

我会用本地 mock 准备正常返回、延迟返回、立即报错和返回无效内容几条路径。每条测试都检查 HTTP 状态或函数结果,也检查日志阶段和资源释放。仅断言“拿到了 Err”太宽松,超时被错误地包装成解析失败也可能通过。

超时发生后,工作是否真的停了

Future 超时返回,不代表所有外部工作都已撤销。若 fetch() 启动了子任务、写入队列或向第三方发送请求,调用方放弃等待后,它们可能继续执行。第一版需要明确这种行为:纯读取可以丢弃迟到结果;带副作用的操作应使用幂等键,并提供结果查询,不能在不知道前一次是否完成时直接重试。

测试里可以让 mock 在超时后记录是否收到取消、连接是否归还。服务关闭时也要确认后台任务有退出条件。若依赖本身不支持取消,就把限制写进接口和运行说明,不用“已经终止”掩盖实际语义。

并发限制应在出现压力前有边界

最小闭环可以不做复杂调度,但不能允许请求无限堆积。入口至少要有请求大小限制和在途任务上限,达到上限时快速返回可识别的繁忙错误。排队如果没有长度和等待上限,只是把超时从依赖层挪到了内存里。

开始时用简单的 semaphore 就够了,容量依据服务资源和实际测量调整。不要因为示例能同时处理几个请求,就把这个数字当成部署参数。观察时区分等待许可的时间与依赖处理时间,才能知道瓶颈在本地还是外部。

闭环的验收方式

我会从入口发起一条正常请求、一条受控慢请求和一条错误响应。正常请求返回可消费结果;慢请求在预算到达时结束等待,并留下明确类别;错误响应不触发无边界重试。随后检查在途计数、连接和子任务都回到预期状态。

做到这里,第一版已经能回答异步链路最实际的问题:成功怎样交付,等待多久,失败如何解释,放弃等待后还剩什么。等日志证明排队、吞吐或隔离确实成了问题,再引入队列和工作池,新增复杂度才有清楚的理由。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值