You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免相同webhook请求触发AWS Lambda函数重复执行业务逻辑

问题根因

你当前的方案是先读再写的非原子操作,三个并发触发的Lambda请求会在几乎同一时间执行check_duplicate_webhook查询,此时所有请求都拿到「未支付」的结果,就会同时执行业务逻辑,后续的更新操作也都会执行,自然无法防重。

解决方案:用DynamoDB条件写入实现原子幂等校验

DynamoDB的ConditionExpression可以把「校验状态是否存在」和「写入新状态」两个操作合并为单个原子操作,只有满足条件的第一个请求能写入成功,其余重复请求会直接抛出异常,完全规避并发问题。

具体改动步骤

  • 删除提前调用check_duplicate_webhook的逻辑,不需要单独做前置查询
  • 给你的更新操作增加条件表达式,要求对应订单的支付状态不存在,或者状态不等于paid
  • 捕获更新操作抛出的ConditionalCheckFailedException,如果触发该异常直接判定为重复请求,终止后续流程即可

修改后的更新代码示例

import boto3
from botocore.exceptions import ClientError

try:
    dynamodb_table_payment.update_item(
        Key={'user_id': user_id},
        UpdateExpression="SET payments.#order_id.#pay_status = :pay_status, "
                         "payments.#order_id.#update_date = :update_date, "
                         "payments.#order_id.reward = :reward_amount",
        # 新增条件表达式:对应订单状态不存在 或者 状态不等于paid,才允许写入
        ConditionExpression="attribute_not_exists(payments.#order_id.#pay_status) OR payments.#order_id.#pay_status <> :pay_status",
        ExpressionAttributeNames={
            "#order_id": attr['order_id'],
            '#pay_status': "status",
            '#update_date': 'updated_at'
        },
        ExpressionAttributeValues={
            ":pay_status": 'paid',
            ':update_date': int(time.time()),
            ':reward_amount': reward_amount
        }
    )
except ClientError as e:
    if e.response['Error']['Code'] == 'ConditionalCheckFailedException':
        # 触发条件校验失败,说明是重复请求,直接退出
        return
    # 其他异常按原有逻辑处理
    log(e)
    raise

# 只有更新操作执行成功,才走后面的业务逻辑
run_your_business_logic()

额外优化建议

如果你的业务逻辑执行有失败概率,可以把状态拆为processing和paid两个阶段,先原子性写入processing占位,执行业务成功后再更新为paid,避免请求失败后没有重试入口。

内容的提问来源于stack exchange,提问作者u_s_e_r

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 18:06:05