我很高兴宣布Swift服务器生态系统的一个新的开源项目,Swift AWS Lambda Runtime。Swift AWS Lambda Runtime以Swift软件包的形式发布,旨在帮助Swift开发者为Amazon Web Services Lambda平台构建无服务器功能。
该项目是一项集体努力,包括整个Swift社区的工程师,包括来自苹果和亚马逊的工程师。值得注意的是,Fabian Fett在社区中开创了这项工作,并共同编写了该库。作为一个开源库,任何有兴趣为该项目做出贡献的人都可以很容易地加入进来,帮助它做得更好。
项目背景
许多现代系统都有客户端组件,如iOS、macOS或watchOS应用程序,以及与这些客户端交互的服务器组件。无服务器函数通常是客户端应用开发者将其应用扩展到云端的最简单、最有效的方式。
无服务器函数正成为在云中运行事件驱动或其他临时计算任务的一个越来越受欢迎的选择。它们为关键任务微服务和数据密集型工作负载提供动力。在许多情况下,鉴于无服务器功能的按需性,它允许开发者更容易扩展和控制计算成本。
在使用无服务器函数时,必须注意资源利用率,因为它直接影响系统的成本。这正是Swift的优势所在。凭借其低内存占用、确定性能和快速启动时间,Swift是无服务器函数架构的绝佳搭配。
结合Swift的开发者友好性、表达能力和对安全的强调,我们就有了一个对各种技能水平的开发者都很好、可扩展且成本低廉的解决方案。
Swift AWS Lambda Runtime旨在使在Swift中构建Lambda函数变得简单而安全。该库是AWS Lambda Runtime API的实现,使用嵌入式异步HTTP客户端,在AWS Runtime上下文中对性能进行了微调。该库提供了一个多层次的API,可以构建一系列的Lambda函数。从快速简单的闭包到复杂的、对性能敏感的事件处理程序。
它是如何工作的?
使用闭包
使用AWS Lambda Runtime的最简单方法是传递一个闭包,例如:
// Import the module
import AWSLambdaRuntime
// In this example we are receiving and responding with strings
Lambda.run { (context, payload: String, callback) in
callback(.success("Hello, \(payload)"))
}
更常见的是,有效载荷将是一个JSON,使用Codable ,例如,它的模型:
// Import the module
import AWSLambdaRuntime
// Request, uses Codable for transparent JSON encoding
private struct Request: Codable {
let name: String
}
// Response, uses Codable for transparent JSON encoding
private struct Response: Codable {
let message: String
}
// In this example we are receiving and responding with JSON using Codable
Lambda.run { (context, request: Request, callback) in
callback(.success(Response(message: "Hello, \(request.name)")))
}
由于Lambda函数经常被来自AWS平台的事件所触发,如SNS、SQS或S3事件,该软件包还包括一个AWSLambdaEvents 模块,为这些常见的触发事件类型提供实现方法。例如,处理一个SQS 消息:
// Import the modules
import AWSLambdaRuntime
import AWSLambdaEvents
// In this example we are receiving a SQS Message, with no response (Void)
Lambda.run { (context, message: SQS.Message, callback) in
...
callback(.success(Void()))
}
除了这些常见的触发事件,AWSLambdaEvents 还包括将Lambda函数与APIGateway集成的抽象--这是一个有助于将Lambda函数暴露为HTTP端点的AWS系统:
// Import the modules
import AWSLambdaRuntime
import AWSLambdaEvents
// In this example we are receiving an APIGateway.V2.Request,
// and respoding with APIGateway.V2.Response
Lambda.run { (context, request: APIGateway.V2.Request, callback) in
...
callback(.success(APIGateway.V2.Response(statusCode: .accepted)))
}
使用EventLoopLambdaHandler
将Lambda函数建模为闭包,既简单又安全。Swift AWS Lambda Runtime将确保用户提供的函数从网络处理线程中卸载到自己的线程中,这样即使代码变得缓慢或无响应,底层Lambda进程也能继续进行并与Runtime引擎互动。这种安全性是以网络和处理线程之间的上下文切换带来的小的性能损失为代价的。在大多数情况下,使用基于闭合的API的简单性和安全性比下面详述的面向性能的API的复杂性更受欢迎。
对性能敏感的Lambda函数可以选择使用更复杂的API,允许用户代码与网络处理程序在同一线程上运行。Swift AWS Lambda Runtime使用SwiftNIO作为其底层网络引擎,这意味着这些API是基于SwiftNIO的并发原语,如EventLoop 和EventLoopFuture 。
例如,处理一个SNS 消息:
// Import the modules
import AWSLambdaRuntime
import AWSLambdaEvents
import NIO
// Our Lambda handler, conforms to EventLoopLambdaHandler
struct Handler: EventLoopLambdaHandler {
typealias In = SNS.Message // Request type
typealias Out = Void // Response type, or Void
// In this example we are receiving a SNS Message, with no response (Void)
func handle(context: Lambda.Context, payload: In) -> EventLoopFuture<Out> {
...
context.eventLoop.makeSucceededFuture(Void())
}
}
Lambda.run(Handler())
除了使用基于EventLoopFuture 的 API 的认知复杂性之外,请注意,使用这些 API 时应格外小心。一个EventLoopLambdaHandler 将在与库的网络引擎相同的EventLoop (线程)上执行用户提供的函数,这就对实现提出了一个要求,即永远不要阻塞底层EventLoop 。换句话说,Lambda代码决不能使用阻塞的API调用,因为它可能会阻止库与Lambda平台进行交互。
项目状态
这是一个社区驱动的开源项目的开始,积极寻求贡献。 虽然核心API被认为是稳定的,但随着接近1.0 。有几个领域需要额外关注,包括但不限于:
- 进一步的性能调整
- 额外的触发事件
- 额外的文档和最佳实践
- 更多的例子