【问题标题】:AWS Lambda: Handling variable input typesAWS Lambda:处理变量输入类型
【发布时间】:2019-03-03 20:27:16
【问题描述】:

当传入 JSON 的格式因触发器类型而异时,处理 AWS Lambda 处理程序函数的输入的标准方法是什么?

例如我有一个 Lambda 函数,当在 S3 存储桶中创建对象时调用该函数, 在触发每小时计划的事件时调用。显然,传递给处理程序的 JSON 格式不同。

是否可以重载 Lambda 处理程序函数,其中一个签名的输入类型定义为 S3Event,另一个签名定义为 ScheduledEvent?如果不是,开发人员是否只是在try 块中调用JsonConvert.DeserializeObject?或者是建立多个 Lambda 函数的标准做法,每个输入类型一个(糟糕!)?

【问题讨论】:

    标签: aws-lambda


    【解决方案1】:

    每个事件你应该使用一个函数。

    为一个 Lambda 设置多个触发器只会让事情变得更加困难,因为如果您想应用设计模式,最终会得到一堆 if/else、switch 语句甚至工厂方法。

    现在将 Lambda 函数视为小型且可维护的。想想应该做一件事并且应该做好的代码片段。当你开始拥有多个触发器时,你最终会得到一个“Lambda Monolith”,因为它有太多的责任。不仅如此,您还可以将 Lambda 函数与您的事件紧密结合,这意味着一旦添加了新触发器,您的 Lambda 代码就会发生变化。这只是在两次或三次触发后无法扩展。

    另一个缺点是,只有当您像这样构建它时,您才必须使用一种语言。对于某些用例,Java 可能是最佳选择。但对其他人来说,可能是 Node JS、Python、Go……

    基本上,您的函数应该足够小,以便于维护,甚至在必要时重写。为每个事件创建一个函数绝对没有错,尽管显然您强烈反对它。将每个 Lambda 视为一个独立的微服务,它可以独立扩展,拥有自己的 CI/CD 管道和自己的测试套件。

    要考虑的另一件事是,如果您想根据触发器类型限制 Lambda 并发执行。这将无法通过“One-Lambda-Does-It-All”模型实现。

    坚持每个触发器使用一个 Lambda,您晚上会睡得更好。

    【讨论】:

    • 嗯,处理不同输入类型的条件语句的场景将通过重载处理程序方法来解决,这就是我询问这种方法的原因。另外,我正在使用 F#,它非常擅长将输入处理为相关但不同的类型,但我会将您的回答作为建议。谢谢。
    • 对于每个触发器一个 lambda,您到底不喜欢什么?
    • 一般来说,我认为每个触发器类型一个 Lambda 就可以了。不过,F# 对联合有很好的支持,因此最好利用不同的触发器作为联合类型——尤其是在代码解析为 Lambda 函数所期望的所有类型统一的东西之前进行最少处理的情况。 (例如,除了处理放入我的 S3 存储桶中的对象之外,我可能希望我的 Lambda 每小时记录一次。为此创建一个全新的 Lambda 意味着复杂性的增加与功能的轻微增加不相称。)
    【解决方案2】:

    这实际上可以通过以下方式实现:

    1. 让 Lambda 签名采用 Stream 而不是 Amazon 事件类型,这样我们就可以获得原始 JSON 消息。
    2. 将流的 JSON 内容作为字符串读取。
    3. 将字符串反序列化为自定义类型以识别事件源。
    4. 使用事件源信息再次将 JSON 反序列化为事件源的适当类型。

    例如:

    public async Task FunctionHandler(Stream stream, ILambdaContext context)
    {
        using var streamReader = new StreamReader(stream);
        var json = await streamReader.ReadToEndAsync();
    
        var serializationOptions = new JsonSerializationOptions { PropertyNameCaseInsensitive = true };
        var awsEvent = JsonSerializer.Deserialize<AwsEvent>(json, serializationOptions);
        var eventSource = awsEvent?.Records.Select(e => e.EventSource).SingleOrDefault();
             
        await (eventSource switch
        {
            "aws:s3" => HandleAsync(Deserialize<S3Event>(json, serializationOptions), context),
            "aws:sqs" => HandleAsync(Deserialize<SQSEvent>(json, serializationOptions), context),
            _ => throw new ArgumentOutOfRangeException(nameof (stream), $"Unsupported event source '{eventSource}'."),
        });
    }
    
    public async Task HandlyAsync(S3Event @event) => ...
    public async Task HandleAsync(SQSEvent @event) => ...
    
    public sealed class AwsEvent
    {
        public List<Record> Records { get; set; }
    
        public sealed class Record
        {
            public string EventSource { get; set; }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-02
      • 1970-01-01
      • 2019-01-30
      • 2020-05-31
      • 2022-08-11
      • 2015-11-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多