华为云 APIG 返回 504,为什么 RDS 里已经有了数据
华为云 APIG 返回 504,为什么 RDS 里已经有了数据
在手机上新增一条待办,转了几秒后提示请求超时。再点一次,列表里却出现了两条相同内容。遇到这种情况,先别急着把重试次数加大:第一次请求可能已经把数据写进数据库,只是结果没有及时送回手机。
华为云鸿蒙实践中心的“云同步待办清单”案例采用 App → APIG → FunctionGraph → RDS for MySQL 的调用链。案例的排障部分提到,注册接口可能提示失败,数据库里却已经建好了账号。顺着这条链路看,网关等待后端的时间、函数执行时间和数据库事务提交时间,各自影响着请求的不同阶段。
504 出现时,写入可能已经完成
假设 APIG 等待后端响应的时间设为 5 秒。函数在第 4 秒提交了事务,第 6 秒才返回结果。客户端会先收到超时,但数据库已经保留了那次写入。这组时间只是说明执行顺序的例子;实际排查要看实例配置和调用日志。
还有一种顺序是,网关先超时,函数随后才完成提交。客户端拿到 504 时,单凭这个状态码无法判断数据最后有没有写进去。网络断开、客户端主动取消,也会带来类似的不确定性。页面显示“提交失败”容易让人立即再点一次,后台如果把每次请求都当成新建,就会多出一条记录。
排查时可以用同一个业务请求标识,把客户端日志、函数日志和数据库记录对应起来。先确认请求有没有到达函数,再看写入是否提交、响应在什么时候生成。日志中记录请求标识和关键阶段即可,密码、会话 token 和完整用户资料都不需要打印。只看函数入口日志,只能证明执行开始;判断提交结果还需要数据库记录或明确的提交日志。
重试时沿用同一个任务 ID
待办清单的创建操作,可以在用户第一次点击保存时生成任务 ID,并把它和待提交内容一起保存在本地。第一次请求超时后,再次发送时继续使用这个 ID。只有用户明确新增另一条任务,才生成新的 ID。
例如,第一次提交的任务 ID 是 demo-task-001,标题是“检查备份”。网络超时后,重试仍然携带 demo-task-001。如果每次重试都重新生成 ID,服务端看到的就是不同任务,数据库的唯一约束也拦不住重复内容。
服务端需要用唯一约束承接这个约定。下面是演示用表结构,表示同一个用户的任务 ID 不能重复:
CREATE TABLE task_retry_demo (
user_id BIGINT NOT NULL,
task_id VARCHAR(36) NOT NULL,
title VARCHAR(200) NOT NULL,
PRIMARY KEY (user_id, task_id)
);
用户标识应由服务端校验会话后取得。客户端传来的 user_id 不能直接决定数据归属,否则只改一个参数就可能读写别人的任务。查询已有记录、处理重复键和返回结果,都应带上当前用户的范围。
遇到重复键时,还要检查这次请求与原请求的含义是否一致。相同 ID、相同创建内容,可以返回已存在的任务;相同 ID 却携带另一份内容,则应提示冲突。直接把重复请求里的标题覆盖进去,会让一条迟到的旧请求覆盖用户后来编辑的内容。创建和修改分开处理,更容易解释每次操作的结果。
如果接口同时发消息、扣减库存或调用其他系统,仅给任务表加唯一约束还不够。数据库提交后进程退出,消息可能尚未发出;反过来,重试也可能再次发送消息。这类操作需要把待发送事件与业务写入放进同一事务,再由后台投递,并让接收方识别重复事件。对普通待办创建,先把一条任务的重复写入处理正确,就已经解决了眼前的问题。
验证“超时后再试”这条路径
可以在测试环境中,让函数在事务提交之后延迟返回,延迟时间超过测试网关的后端超时配置。客户端收到 504 后,使用原来的任务 ID 重试,再检查数据库:应当只有一条任务,两次请求最终应指向同一条记录。测试结束后恢复超时配置并移除人为延迟。
还要补两个容易漏掉的场景:两次相同请求同时到达,以及同一个任务 ID 携带不同内容到达。前者检查数据库唯一约束是否生效,后者检查服务端有没有把冲突当成普通重试。用另一个测试账号提交相同 ID,则可以验证数据归属是否正确。
华为云案例中还记录了 VPC 函数冷启动超过网关后端等待时间的现象。调整超时前,先看冷启动和正常调用各自的耗时,确认等待时间是否符合接口需求。延长等待时间能减少一部分超时;网络中断和响应丢失仍然可能发生,写接口的重试行为仍需单独验证。
页面文案也可以据此调整。暂时拿不到结果时,显示“正在确认提交结果”,随后按任务 ID 查询,比立刻提示用户重新新增更合适。查到记录就展示已有任务;仍需重试时,沿用原请求标识,让用户的一次保存操作始终对应同一条数据。
参考:华为云鸿蒙开发实践中心《云同步待办清单:鸿蒙端云一体实战》,其中的“注册提示失败,数据库里却已经建了账号”及“幂等写入与越权防护”部分。本文在该案例问题的基础上讨论重试设计,示例表结构用于说明约束。
https://harmonybp.developer.huaweicloud.com/cases/18f755e68ca24c298b5efb8533ef6a44
- 点赞
- 收藏
- 关注作者
评论(0)