WWDC Quick Look 💓 By SwiftGGTeam
Use Swift on AWS Lambda with Xcode

Use Swift on AWS Lambda with Xcode

观看原视频

Highlight

Swift AWS Lambda Runtime 让开发者用 Swift 编写 AWS Lambda 函数,在 Xcode 里用本地 runtime simulator 调试,并通过 Amazon Linux 2 Swift toolchain 打包部署到 AWS Lambda。

核心内容

很多 Apple 平台 App 都有一段服务器端逻辑。客户端负责界面和设备能力,服务器端负责访问设备上没有的数据、处理后台任务,或者承接计算量更重的工作。问题是,两端常常使用不同语言、不同工具链、不同调试方式,团队也会被切成客户端和服务器端两套节奏。

Serverless function(无服务器函数)把这件事缩小到一个事件处理函数。AWS Lambda 接收事件,按需分配计算资源,空闲时不需要开发者自己维护专用服务器。演讲里给出的判断很直接:计算资源使用率会影响系统成本,而 Swift 的低资源占用和开发友好性适合这类短小、事件驱动的任务。

Apple 展示的方案是 Swift AWS Lambda Runtime。开发者在 Swift Package 里写一个 executable product,引入 runtime library,然后用 Lambda.run 注册处理逻辑。最小版本只有一个闭包;性能敏感版本可以接入 NIO 的 EventLoop;常见 JSON payload 可以直接交给 Codable 类型。

真正改变开发体验的是本地调试。演讲的 demo 把 Lambda 和 iOS app 放在同一个 Xcode workspace 里。开发者给 Lambda target 设置 LOCAL_LAMBDA_SERVER_ENABLED=true,runtime 会在本机启动一个模拟 AWS Lambda runtime engine 的 HTTP server,监听 localhost:7000 的 invoke endpoint。Xcode 同时管理 iOS app 和 Lambda 两个进程,断点能从客户端请求一路打到 Lambda 处理函数,再回到客户端响应处理。

部署流程也没有离开 Swift。示例脚本创建基于 Swift.org Amazon Linux 2 image 的 Docker image,在容器里编译 Lambda executable,把可执行文件和依赖打成 AWS Lambda 需要的 zip,再通过 AWS CLI 上传并通知新代码版本。上线后,AWS Lambda runtime engine 负责拉取 work、调用用户函数、提交结果;API Gateway、S3、SQS、SNS 或自定义事件都可以成为触发入口。

详细内容

用闭包写最小 Lambda

02:02)最小 API 从 AWSLambdaRuntime 开始。Lambda.run 接收一个闭包,闭包拿到 context、事件 payload 和 completion handler。runtime library 管理程序生命周期,并负责和底层平台交互。

import AWSLambdaRuntime

Lambda.run { (_, name: String, callback) in
    callback(.success("Hello, \(name)!"))
}

关键点:

  • import AWSLambdaRuntime 引入 Swift AWS Lambda Runtime library。
  • Lambda.run 注册 Lambda 的处理入口,runtime 会在事件 payload 可用时调用它。
  • 第一个参数是 context,这个最小示例没有使用,所以写成 _
  • name: String 是事件 payload,示例把它当作字符串输入。
  • callback(.success(...)) 在工作完成后把结果交回 runtime。

用 EventLoop 处理性能敏感场景

02:33)第二个 API 是 protocol-oriented 写法,面向性能敏感 use case。它暴露 NIO EventLoop,让 Lambda 处理函数和 networking processing stack 共享同一条线程,从而减少 context switch。代价是 handler 不能阻塞 event loop。

import AWSLambdaRuntime
import NIO

struct Handler: EventLoopLambdaHandler {
    typealias In = String
    typealias Out = String

    func handle(context: Lambda.Context, event: String) -> EventLoopFuture<String> {
       context.eventLoop.makeSucceededFuture("Hello, \(event)!")
    }
}

Lambda.run(Handler())

关键点:

  • EventLoopLambdaHandler 是面向 EventLoop 的 handler 协议。
  • typealias Intypealias Out 声明输入、输出类型,这里都是 String
  • handle(context:event:) 返回 EventLoopFuture<String>,结果交给 NIO 的异步模型。
  • context.eventLoop.makeSucceededFuture(...) 在当前 event loop 上创建成功 future。
  • Lambda.run(Handler()) 把结构体 handler 交给 runtime 运行。

用 Codable 处理 JSON payload

02:59)演讲随后把字符串 payload 换成 request / response 结构体。Lambda payload 通常基于 JSON,Swift 的 Codable 可以完成 JSON 与 Swift 类型之间的序列化。

import AWSLambdaRuntime

struct Request: Codable {
    let name: String
    let password: String
}

struct Response: Codable {
    let message: String
}

Lambda.run { (_, request: Request, callback) in
    callback(.success(Response(message: "Hello, \(request.name)!")))
}

关键点:

  • Request 表示输入事件,演讲里的 demo 用它承载注册表单的 namepassword
  • Response 表示 Lambda 返回给客户端的 JSON 结果。
  • 两个类型都遵循 Codable,runtime 可以把 JSON payload 转成 Swift 类型,再把 Swift 结果转回 JSON。
  • 闭包参数 request: Request 让处理函数直接面对业务类型。
  • Response(message: ...) 是返回值,completion handler 把它交回 runtime。

在 Xcode 里调试客户端和 Lambda

04:22)演讲的 Xcode demo 用一个 workspace 放两个项目:一个 Lambda package manager project,一个 iOS app。Lambda target 直接运行会报错,因为本地没有真正的 AWS Lambda runtime engine。解决方式是编辑 scheme,把 LOCAL_LAMBDA_SERVER_ENABLED 设为 true

05:09)再次运行后,本地 server 会监听 localhost:7000,并在 invoke endpoint 接收事件。iOS app 通过 URLSession 向这个地址发送注册请求。Xcode 同时管理两个进程:iOS app 和 Lambda function。演讲里依次在构造 request、进入 Lambda function、处理 response 三处命中断点,还用 LLDB 检查返回值。

07:08)这个调试模式只用于本地。要让已部署 Lambda 通过 HTTP 被客户端访问,需要先通过 AWS API Gateway 暴露 endpoint。demo 的重点是开发阶段:客户端和云端函数可以在同一个 Xcode 调试会话里串起来。

打包并部署到 AWS Lambda

07:53)部署 demo 使用一个包装 AWS CLI 的脚本。脚本先创建基于 Swift.org Amazon Linux 2 image 的 Docker image,再在容器里编译 Lambda function。随后它把 executable 和依赖打成 zip,这正是 AWS Lambda 期望的包格式,最后上传 zip 并通知新的 code version。

09:33)这套部署能力依赖两个基础组件。第一,Swift.org 从 2020 年 5 月开始发布面向 Amazon Linux 2 的 Swift toolchain,可用于 EC2 和 AWS Lambda 等 AWS compute service。第二,Swift Lambda runtime library 实现了 AWS Lambda runtime API,提供从简单闭包到性能敏感 event handler 的多层 API。

10:14)runtime library 内部包含 Lifecycle Loop 和状态机,负责从 runtime engine queue 拉取 work、把 work 交给用户函数、再把结果提交回 runtime engine。它还内嵌一个为 AWS Lambda runtime context 调优的 asynchronous HTTP client。编译后的程序把用户代码、runtime library 和 Swift dependencies 链接成 executable,依需求可以静态或动态链接。

11:15)AWS Lambda 可以按需求运行多个 serverless function 副本,所以函数应该保持 stateless。演讲特别提醒要避免 global mutable state,也要避免持有超过需要时间的内存。触发入口可以来自 S3、SQS、SNS、通过 API Gateway 暴露的 HTTP endpoint,或者用户添加的自定义事件。

核心启发

  • 做一个 Swift 写的注册后端:把 iOS 注册表单提交给 Swift Lambda,输入用 Request: Codable,输出用 Response: Codable。为什么值得做:演讲完整演示了 iOS app 用 URLSession 调本地 Lambda,并在 Xcode 里跨两个进程断点调试。怎么开始:先用本地 LOCAL_LAMBDA_SERVER_ENABLED=true 调通 localhost:7000,上线时再通过 API Gateway 暴露 HTTP endpoint。

  • 把重计算任务从客户端移到 Swift Lambda:把设备上不适合即时执行的后台任务或计算任务交给 serverless function。为什么值得做:transcript 明确把 server component 的价值放在访问云端数据、后台任务和计算密集任务上,Swift 的低资源占用也适合按需计算。怎么开始:用 closure-based Lambda.run 做第一个版本,确认 payload 和返回值后,再用 Amazon Linux 2 Docker image 打包部署。

  • 做事件驱动的云端处理管线:让 S3、SQS、SNS 或自定义事件触发 Swift Lambda。为什么值得做:runtime library 提供 extensible integration points,演讲列出了这些 AWS event source。怎么开始:先定义事件 payload 的 Codable 类型,再根据处理耗时选择闭包 API 或 EventLoopLambdaHandler

  • 做一套客户端与 Lambda 的本地调试模板:把 iOS app 和 Lambda package 放进同一个 Xcode workspace,预置 scheme 环境变量和断点位置。为什么值得做:演讲证明 Xcode 可以同时管理客户端和 Lambda 两个 executable target,调试请求和响应更直接。怎么开始:复制 demo 的结构:Lambda executable product 依赖 Swift AWS Lambda Runtime,客户端用 URLSession 调本地 invoke endpoint。

关联 Session

评论

GitHub Issues · utterances