【问题标题】:Lambda function is triggering twice on DynamoDB eventLambda 函数在 DynamoDB 事件上触发了两次
【发布时间】:2019-08-02 15:33:26
【问题描述】:

我有附加到 DynamoDB 更改事件的 Lambda 函数。 当我更改/修改 DynamoDB 的 Test-machines 表中的项目时,Lambda 会触发两次。

我正在将IsMachineOn 的值从True 修改为False,这是两次触发Test-Machine-On-alert-status Lambda 函数。

我不明白为什么两次 lambda 是触发器。

我观察到 Lambda 的 event 参数中的 records 有一个小的变化。

对于第一次触发

NewImage["IsMachineOn"]["BOOL"] 的值为 False

OldImage["IsMachineOn"]["BOOL"] 的值为 True

对于第二次触发

NewImage["IsMachineOn"]["BOOL"] 的值为 False

OldImage["IsMachineOn"]["BOOL"] 的值为 False

我在NewImage["IsMachineOn"]["BOOL"]==False 上有业务逻辑,因此我的业务逻辑运行了两次。

有两件事:

  1. 为什么 Lambda 运行两次?
  2. 有什么办法可以解决此问题?

【问题讨论】:

  • 为了保证至少交付一次,这个多次调用的东西将probably happen。关键是,我们是否应该认为您的 Lambda 函数是非幂等的?如果是这样,将其设为一个将是一种解决方法。
  • @vahdet:我的 Lambda 函数不是幂等的。每次请求 id 都不一样。
  • 这种行为并不一定会让你的代码具有幂等性,但无论如何;如果你严格要求只发射一次,我现在想不出解决办法。
  • 您的逻辑当然应该测试NewImage["IsMachineOn"]["BOOL"] == False && NewImage["IsMachineOn"]["BOOL"] != OldImage["IsMachineOn"]["BOOL"](现在关闭,这也是一个状态更改事件)......但听起来好像第二个不同的更新正在触发第二个事件,因此,您可能应该查看其他属性,以确定第二个事件触发器的性质。这不能 - 根据定义 - 是同一事件上的第二个 Lambda 触发器,如果​​新旧的一个不同而另一个相同。
  • 关于这个主题有一篇很好的博文:cloudonaut.io/… 从中学到的主要内容:确保你的 Lambda 函数是幂等的,并且可以处理潜在的多次执行。

标签: aws-lambda amazon-dynamodb


【解决方案1】:

我们在使用全局表在多个区域的 dynamodb 表之间同步数据时发现了这个问题。我们的假设是,在区域之间同步数据后,第二次推送是由全局表进行的。我写了一个简单的代码来检查新旧图像是否真的不同,只有当它们不同时才处理事件

def check_if_dynamo_entities_are_same(dyanmoStreamEvent):
    '''copying so that we dont change the incoming event'''
    dyanmoStreamEventCopy = copy.deepcopy(dyanmoStreamEvent)
    if( not 'NewImage' in dyanmoStreamEventCopy['dynamodb'] or not 'OldImage' in dyanmoStreamEventCopy['dynamodb']):
        logger.info("one of newimage or oldimage is not present returning true")
        return False
    remove_aws_keys(dyanmoStreamEventCopy['dynamodb']['NewImage'])
    remove_aws_keys(dyanmoStreamEventCopy['dynamodb']['OldImage'])
    return compare_two_json(dyanmoStreamEventCopy['dynamodb']['NewImage'], dyanmoStreamEventCopy['dynamodb']['OldImage'])

def remove_aws_keys(dic):
    for k in dic.copy():
        if k.startswith('aws:'):
            logger.info("poping key=%s", k)
            dic.pop(k)

def ordered(obj):
    if isinstance(obj, dict):
        return sorted((k, ordered(v)) for k, v in obj.items())
    if isinstance(obj, list):
        return sorted(ordered(x) for x in obj)
    else:
        return obj


def compare_two_json(json1, json2):
    """This method return true or false if the given jsons are equal or not.
    This has been taken from https://stackoverflow.com/a/25851972/3892213"""
    return ordered(json1) == ordered(json2)

【讨论】:

    【解决方案2】:

    我也会检查记录是否已更改! 因此我在 Python 3.6 中编写了以下代码

    old_sites = set()
        new_sites = set()
    
        # Calculate the disjoint quantity of NEW & OLD mappings
        for image_name in ['OldImage', 'NewImage']:
            if record['dynamodb'] is not None and image_name in record['dynamodb']:
                ddb_entry = record['dynamodb'][image_name]
                mappings = ddb_entry[value_key]['L']
                print(f"mappings: {mappings}")
    
                for mapping in mappings:
                    old_sites.add(mapping['S']) if image_name == 'OldImage' else new_sites.add(mapping['S'])
    
        changed_mappings = old_sites.symmetric_difference(new_sites)
    

    【讨论】:

      【解决方案3】:

      我们的 DynamoDB 全局表遇到了同样的问题。我们观察到双重事件仅发生在您创建update 的区域,其他区域仍然收到 1 个事件,这很棒。

      您得到 2 个事件的原因是 DynamoDB 需要维护一些内置字段以防止区域无限地相互更新的循环。

      1. 第一个事件是更新存储的 real 对象/字段的属性,在您的情况下是 IsMachineOn,它从 true 更改为 false

      2. 第二个事件正在更新特殊属性,例如aws:rep:deletingaws:rep:updatetimeaws:rep:updateregion。这就是为什么您会看到旧/新图像都有 IsMachineOn 作为 false 这是 new 值。

      希望这有助于澄清一些事情。这让我困惑了好几个小时。

      TL;DR...

      通常您可以只比较旧/新图像的aws:rep:updatetime,如果它们相同,那么就是更新 aws internal 字段的事件,因此您可以忽略。

      在我们的用例中,我们依靠aws:rep:updateregion 来确保某些逻辑只运行一次(而不是在多个区域中),因此我们必须比较旧/新的aws:rep:updatetime 以忽略第一个具有以前的地区信息。好消息是两个事件的 图像都具有我们存储的对象的正确值。

      2020 年 7 月 23 日更新

      • 我们注意到的另一个重要点是,如果您使用put() 更新/创建记录,则第一个事件的新图像以及第二个事件的旧图像中将缺少 aws 内置字段.如果您依赖这些字段,最好将update() 用于现有记录,以确保它们始终存在。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-29
        • 1970-01-01
        • 2021-12-28
        • 2016-04-19
        • 2014-08-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多