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

AWS Lambda无错误重复调用问题求助(单次请求触发4次调用)

问题描述

我有一个用于币安期货交易的AWS Lambda函数,预期单次请求仅触发一次函数执行,但实际出现了4次独立调用(每次请求ID均不同),排除了错误重试的可能。我已经调整过Lambda配置中的超时时间和重试次数,但问题仍未解决,求可行的解决思路。

函数代码如下:

from binance import Client
import os

def get_position_amt(bot, symbol):
    get_position = bot.futures_position_information(symbol=symbol)
    amt = float(get_position[0]['positionAmt'])
    
    return amt
    

def close_all_position(bot, symbol):
    print('close_all_position')
    amt = get_position_amt(bot, symbol)
    if amt > 0:
        close_order = bot.futures_create_order(
            symbol=symbol, side="SELL", type="MARKET", quantity=amt
            )
        print(close_order)
    elif amt < 0:
        close_order = bot.futures_create_order(
            symbol=symbol, side="BUY", type="MARKET", quantity=abs(amt)
            )
        print(close_order)
    else:
        print("no position : amt is zero")
        

def lambda_handler(event, context):
    
    bot = Client(api_key=os.environ.get('api_key'), api_secret=os.environ.get('api_sc'))
    
    data = eval(event['body'])
    
    side=data.get('side')
    symbol=data.get('market')
    amt = get_position_amt(bot, symbol)
    if side == "BUY":
        if amt < 0:
            close_all_position(bot, symbol)
    elif side == "SELL":
        if amt > 0:
            close_all_position(bot, symbol)

    ord_type = data.get('ord_type')
    if ord_type == 'limit':
        order = bot.futures_create_order(
        symbol=data.get('market'), side=data.get('side'), type="LIMIT", timeInForce='GTC', quantity=float(data.get('volume')), price=float(data.get('price'))
        )
        print(order)
    elif ord_type == 'market':
        order = bot.futures_create_order(
        symbol=data.get('market'), side=data.get('side'), type="MARKET", quantity=float(data.get('volume'))
        )
        print(order)
    elif ord_type == 'close':
        close_all_position(bot, data.get('market'))
    else:
        raise ValueError
解决思路
  • 排查触发源的重复请求
    先确认调用Lambda的上游服务(如API Gateway、SQS、CloudWatch Events等)是否发送了重复请求。比如API Gateway若遇到客户端重试、多AZ冗余转发等情况,会导致多次Lambda调用。可以查看触发源的日志(如API Gateway访问日志),确认是否存在多个相同请求被发送。

  • 检查事件源映射配置
    如果Lambda通过事件源(如SQS、Kinesis)触发,检查事件源映射的批量大小、重试配置,是否存在消息被重复读取的情况。另外,SQS的可见性超时若小于Lambda执行时间,会导致消息被重新处理,引发多次调用。

  • 添加幂等性处理(关键)
    交易场景必须保证操作幂等,避免重复执行带来的风险。可以在请求中加入唯一请求ID,Lambda执行前先检查该ID是否已处理(比如存储到DynamoDB),若已处理则直接返回,不执行交易逻辑。示例修改如下:

    from binance import Client
    import os
    import boto3
    from datetime import datetime
    
    dynamodb = boto3.resource('dynamodb')
    idempotency_table = dynamodb.Table('LambdaIdempotencyTable') # 需提前创建该DynamoDB表
    
    def get_position_amt(bot, symbol):
        get_position = bot.futures_position_information(symbol=symbol)
        amt = float(get_position[0]['positionAmt'])
        return amt
        
    # 保留原有close_all_position函数
    
    def lambda_handler(event, context):
        # 提取或生成唯一请求标识,优先用请求自带的ID,无则用Lambda请求ID
        request_id = event.get('requestId') or context.aws_request_id
        
        # 检查请求是否已处理
        try:
            response = idempotency_table.get_item(Key={'request_id': request_id})
            if 'Item' in response:
                print(f"Request {request_id} already processed")
                return {'statusCode': 200, 'body': 'Request processed'}
        except Exception as e:
            print(f"Check idempotency failed: {e}")
            raise
        
        # 执行原有交易逻辑
        bot = Client(api_key=os.environ.get('api_key'), api_secret=os.environ.get('api_sc'))
        data = eval(event['body'])
        
        side=data.get('side')
        symbol=data.get('market')
        amt = get_position_amt(bot, symbol)
        if side == "BUY":
            if amt < 0:
                close_all_position(bot, symbol)
        elif side == "SELL":
            if amt > 0:
                close_all_position(bot, symbol)
    
        ord_type = data.get('ord_type')
        if ord_type == 'limit':
            order = bot.futures_create_order(
            symbol=data.get('market'), side=data.get('side'), type="LIMIT", timeInForce='GTC', quantity=float(data.get('volume')), price=float(data.get('price'))
            )
            print(order)
        elif ord_type == 'market':
            order = bot.futures_create_order(
            symbol=data.get('market'), side=data.get('side'), type="MARKET", quantity=float(data.get('volume'))
            )
            print(order)
        elif ord_type == 'close':
            close_all_position(bot, data.get('market'))
        else:
            raise ValueError
        
        # 标记请求已处理
        try:
            idempotency_table.put_item(
                Item={'request_id': request_id, 'processed_at': datetime.now().isoformat()}
            )
        except Exception as e:
            print(f"Mark request processed failed: {e}")
        
        return {'statusCode': 200, 'body': 'Success'}
    
  • 查看CloudTrail日志溯源
    通过AWS CloudTrail查看Lambda的调用记录,确认每次调用的发起者(是AWS内部服务还是外部请求),精准定位重复调用的源头。

  • 检查第三方回调机制
    如果Lambda是被第三方服务(如币安Webhook)触发,确认第三方是否存在回调超时重试机制。这种情况下需要确保Lambda在处理完成后返回明确的成功响应(如200状态码),避免第三方重复回调。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 08:50:31