最大努力通知案例

wen java案例 1

本文目录导读:

最大努力通知案例

  1. 案例一:支付宝/微信支付回调(最经典)
  2. 案例二:银行代扣 / 转账结果通知
  3. 案例三:第三方登录(如QQ/微信登录的授权回调)
  4. 案例四:物流状态同步(快递100 / 菜鸟)
  5. 具体代码逻辑示例(伪代码/概念示意)
  6. 最大努力通知的特征

最大努力通知是分布式事务中一种最终一致性的解决方案,它的核心思想是:发起通知方(本地事务)尽可能地将事件结果通知给接收方,如果接收方未确认,则不断地重试,直到成功或达到重试上限。

它与可靠消息最终一致性方案的区别在于,最大努力通知不保证100%成功,也不要求接收方必须消费消息,它只负责“尽力而为”,它通常适用于对数据一致性要求不那么严格(如非核心链路)或跨机构(无法使用MQ)的业务场景。

以下是几个经典的最大努力通知案例:


支付宝/微信支付回调(最经典)

场景描述: 用户在电商平台下单,跳转到支付宝或微信支付,支付成功后,支付宝(或微信)需要通知电商平台的后台系统“这笔订单已经支付成功”,以便平台发货。

为什么用最大努力通知?

  1. 支付宝是第三方机构,电商平台无法部署支付宝的消息队列(MQ),也无法监控支付宝的内部事务。
  2. 支付宝只需要保证“通知到了”或者“通知不到就多次重试”,至于电商平台是否成功处理(比如是否成功更新库存),支付宝并不关心,只要平台返回了“处理成功”的标志,支付宝就不再重复通知。

执行流程(最大努力通知的典型过程):

  1. 第一阶段(正常通知): 用户支付完成,支付宝生成支付结果。
  2. 第二阶段(主动通知-尽力): 支付宝调用电商平台提供的回调接口(HTTP POST),发送支付成功的消息。
    • 电商平台收到后,处理本地业务(修改订单状态),返回“success”字符串。
    • 支付宝收到“success”,停止通知。
  3. 第三阶段(定时补偿-重试): 如果支付宝没有收到“success”(网络超时、接口异常、平台宕机),支付宝会启动定时任务
    • 按照一定的策略(15分钟、15分钟、30分钟、3分钟、10分钟…)进行间隔递增的重试
    • 重试次数有限制(例如最多重试24次)。
  4. 第四阶段(人工兜底/对账): 如果重试了24次依然失败(比如平台服务器停机了一整天),支付宝放弃通知(尽力了),电商平台必须通过主动查询接口(主动拉取订单状态)或人工对账来弥补这笔漏单,这也是为什么支付接口要提供“查询订单状态”API的原因。

该案例中的要点:

  • 发起方(支付宝):只负责推送和重试,不保证接收方一定处理成功。
  • 接收方(电商平台):必须提供幂等接口(重复通知不会导致重复发货),且需要主动查询作为兜底。

银行代扣 / 转账结果通知

场景描述: 电商平台与某银行合作,进行用户账户的余额代扣,银行扣款成功后,需要将“扣款成功”的结果发给电商平台。

为什么用最大努力通知? 银行系统的可靠性要求极高,往往处于内网隔离状态,不允许外部系统直接接入银行内部MQ,银行通常只对外提供基于WebService或HTTP的开放接口,对于银行来说,只要把结果发出来了,就完成了“最大努力通知”。

执行流程:

  1. 电商平台调用银行API发起代扣。
  2. 银行扣款成功,记录扣款流水。
  3. 银行系统异步调用电商平台提供的回调地址。
  4. 若回调失败,银行内部定时任务开始重试(初始间隔短,随后变长)。
  5. 若最终重试失败,银行停止通知,电商平台需要在第二天跑批时,通过“银行文件”或“查询接口”核对流水,发现这笔未确认的扣款,主动补单。

第三方登录(如QQ/微信登录的授权回调)

场景描述: 用户在APP点击“微信登录”,跳转至微信授权页,用户确认后,微信服务器将授权码或用户信息通过302跳转回调给APP服务器。

为什么用最大努力通知? 如果APP服务器在接收到回调时刚好宕机,微信服务器会放弃通知(它只会通知一次,没有重试机制),APP客户端会一直等待,但由于微信没有重试机制,APP这边就需要主动拉取用户信息(主动查询)。

对比分析: 这个案例是“最大努力通知”的退化版,因为很多开放平台(如OAuth2.0协议)规定回调只发一次,没有重试机制,一旦失败,只能靠APP前端定时轮询后端接口来触发补偿,这同样体现了“尽力而为,不保证成功”的核心思想。


物流状态同步(快递100 / 菜鸟)

场景描述: 电商平台对接第三方物流平台(如快递100),用户下单后,物流轨迹信息发生变化(揽收、运输、派送、签收),物流平台需要将最新的轨迹推送给电商平台。

为什么用最大努力通知? 物流数据量巨大,且实时性要求不高(晚几分钟没关系),但绝对不允许数据丢失导致用户体验差,物流平台会定期推送,如果推送失败,只会重试几次,如果一直失败,电商平台只能通过定时任务去物流平台拉取最新轨迹来兜底。


具体代码逻辑示例(伪代码/概念示意)

以下以一个模拟支付回调的后端处理逻辑,展示“最大努力通知”中接收方(电商平台)如何配合。

// 版本一:接收方(电商平台)的回调接口(需要满足幂等性)
@RestController
public class PayCallbackController {
    @Autowired
    private OrderService orderService;
    /**
     * 支付宝/微信回调我们的接口
     * 要求:处理完业务后,必须返回"SUCCESS"给支付平台,否则支付平台会重试
     */
    @PostMapping("/api/pay/notify")
    public String handlePayNotify(@RequestBody Map<String, String> params) {
        // 1. 验签(保证是支付平台发的)
        boolean signOk = payService.verifySign(params);
        if (!signOk) {
            // 验签失败,直接返回FAILURE,让支付平台重试(虽然可能重试也没用,但会导致一直重试)
            return "FAILURE";
        }
        // 2. 根据订单号查询本地订单,判断订单状态
        String orderId = params.get("orderId");
        Order order = orderService.getByOrderId(orderId);
        // 3. 幂等性检查:如果订单状态已经是"已支付",说明之前处理过了,直接返回成功,避免重复发货
        if ("PAID".equals(order.getStatus())) {
            return "SUCCESS";
        }
        // 4. 执行业务(修改订单状态、扣库存)
        orderService.markOrderPaid(orderId);
        // 5. 处理成功,告诉支付平台别再调用我了
        // 注意:这里如果扣库存失败,我们应该返回"FAILURE"让支付平台重试
        return "SUCCESS";
    }
}

最大努力通知的特征

特征维度 说明
保证性 不保证100%送达,只保证“尽力”。
实时性 有一定的延迟,依赖定时任务的重试间隔。
业务敏感性 适用于非实时非核心跨机构(无法用MQ)的场景。
可靠性依赖 必须依赖接收方主动查询(兜底)对账系统来保证最终一致性。
技术实现 通常是 HTTP/WebService调用 + 定时任务重试 + 状态标志位,不依赖MQ中间件(或仅用MQ辅助解耦)。

在实际微服务架构中,最大努力通知通常用于处理“回调类”业务,如果是公司内部系统,更推荐的还是RabbitMQ/Kafka等可靠消息中间件,但一旦涉及和外部(银行、第三方支付、物流)对接,最大努力通知几乎是唯一的选择。

抱歉,评论功能暂时关闭!