如何在 Kotlin 上创建 AWS Lambda 函数?

Gle*_*iko 2 java amazon-web-services node.js kotlin aws-lambda

AWS Lambda 函数是否提供对 Kotlin 语言的支持?目前 Lambda 函数创建向导在运行时下拉列表中不包含 Kotlin 选项:

在此处输入图片说明

但是有 Java 8 和不同的 Node.js 版本。哪个平台更适合在 AWS Lambda 上下文中使用 Kotlin 编写的函数 - JVM 或 Node.js?我可以使用哪些 Kotlin 框架来编写 Lambda 函数?

Rya*_*cox 6

在 Javaland 中,如果您将 Kotlin 程序放在服务器上,您应该将其制作为 fat jar,这样您就可以在任何 JVM 上执行它,而不必担心对 Kotlin 的显式支持。

或者,如果您不想支付 AWS Lambda 冷启动的 JVM 启动成本,您可以考虑使用针对 Node.js 运行时的 Kotlin,而不是 JVM。但我在这里会采取几乎完全相同的方法:在构建服务器上将 Kotlin 编译为 Javascript,打包(现在)Javascript + NPM 模块并将其发送到 Lambda。这可能有效,也可能无效,具体取决于您编写的代码量(假设 Java 包)...

所以,我认为你的问题的答案有两个:

  1. 您有多关心冷启动所需的时间?/ 您多久会进行一次冷启动与温暖的请求?
  2. 您的应用程序对 Java 的依赖程度如何?

但在这两种情况下,您都不需要对 Kotlin 的显式支持,只需要编译过程生成的字节码(JVM 或 Javascript/Node)


mad*_*ead 5

科特林/JVM

在 Kotlin 上创建 AWS Lambda 函数的最自然方法是使用 Kotlin/JVM 并以 Java 8 Lambda 运行时为目标。Kotlin 与 Java 的互操作真的很棒。JVM Lambda 函数应打包在胖 JAR 中,即包含所有依赖项的 JAR 文件。使用 Gradle 很容易做到:

build.gradle.kts:

plugins {
    kotlin("jvm").version("1.3.41") // (1)
    id("com.github.johnrengelman.shadow").version("5.1.0") // (2)
}

repositories {
    jcenter()
}

dependencies {
    implementation(kotlin("stdlib-jdk8")) // (3)
    implementation("com.amazonaws:aws-lambda-java-core:1.2.0") // (4)
}

Run Code Online (Sandbox Code Playgroud)
  1. 支持构建 JVM 工件的标准 Kotlin/JVM 插件
  2. 胖 JAR 的影子插件
  3. 运行时需要Kotlin 的 stdlib。这里我们使用一个用 JDK 8 编译的。
  4. 该工件提供了一些接口以在 Java Lambda 函数中实现。

然后只需创建一个处理程序:

处理程序.kt:

class Handler : RequestHandler<Input, Output> { // (1)
    override fun handleRequest(input: Input, context: Context): Output {
        println(input)

        return Output()
    }
}

Run Code Online (Sandbox Code Playgroud)
  1. 该库为您提供了一个通用RequestHandler类。您所要做的就是实现它的单一方法handleRequestInput并且Output 可以是您的 POJO (POKO),只需确保它们可以与 Jackson 进行序列化和反序列化(Lambda 的文档没有隐式提及它,但如果出现问题,您会在日志中看到 Jackson 提及);或原始类型;或一些预定义的类。

此处查看完整的代码示例:它包含一个可与API Gateway 中的 Lambda 代理集成一起使用的函数。

Kotlin/JVM 就是这样。好简单。

科特林/JS

我不是 Kotlin/JS 专家,但您也可以针对 Node.js 运行时,尽管它不像 JVM 那样简单。

我们的想法是将您的 Kotlin 代码编译(转译)为 JavaScript,并将其部署为通常的 JavaScript Lambda 函数(即 ZIP)。

处理程序可能如下所示:

处理程序.kt

import kotlin.js.json

@JsName("handle")
fun handle(input: dynamic, context: dynamic): dynamic {
    println(JSON.stringify(input))

    val result: dynamic = json(
            "statusCode" to 307,
            "headers" to json(
                    "Location" to "https://google.com"
            )
    )

    return result
}
Run Code Online (Sandbox Code Playgroud)

完整的示例可以在这里找到。它的作用与上面的 Kotlin/JVM Lambda 函数相同(响应重定向),但它在 Node.js 10.x 运行时上运行。

Kotlin/JS 的项目设置稍微困难一些:您需要将转译的 JS 与依赖项 ( node_modules)打包到ZIP 文件中。可能有很多方法可以做到这一点,您可以在此处查看其中一种。

奖励:Kotlin/Native!

亚马逊在AWS re:Invent 2018发布了Lambda Runtime API 。它允许开发人员通过所谓的自定义运行时使用他们想要的任何技术构建 Lambda 函数等。是的,现在可以在 PHP、Perl、Pascal(任何人?)甚至 Bash(他们在文档中使用它)上编写函数!

自定义运行时函数的工作方式与通常的函数略有不同。运行时的工作是:

  1. 执行函数的初始化逻辑。对于 Java,这意味着启动 JVM、加载类并运行静态初始化程序。
  2. 找到通过“Handler”配置参数传递的处理程序。
  3. 为每个传入事件执行处理程序。

下面这张图可以帮助你掌握一个函数的生命周期:

自定义运行时生命周期

一个非常基本的处理程序可能如下所示:

处理程序.kt :

fun main() = runBlocking { // (1)
    val client = HttpClient(Curl) // (2)

    while (true) { // (3)
        val invocation = client.call("http://${getenv("AWS_LAMBDA_RUNTIME_API")!!.toKString()}/2018-06-01/runtime/invocation/next") {
            method = HttpMethod.Get
        } // (4)

        // (5)
        val invocationId = invocation.response.headers["Lambda-Runtime-Aws-Request-Id"]

        // (6)
        client.call("http://${getenv("AWS_LAMBDA_RUNTIME_API")!!.toKString()}/2018-06-01/runtime/invocation/$invocationId/response") {
            method = HttpMethod.Post
            body = TextContent(
                    "{\"statusCode\": 307, \"headers\": {\"Location\": \"https://google.com\"}}",
                    ContentType.Application.Json
            )
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 只要我们使用 Ktor 的协程,我们就需要一个协程范围。获得一个的最简单方法是runBlocking
  2. 使用Curl引擎配置 HTTP 客户端。这是本文开头图片中的初始化阶段。
  3. 进入事件循环。
  4. 获取下一个要处理的事件。
  5. 解析事件。感觉比 grep 好,不是吗?
  6. 通过调用 AWS 的 REST API 进行响应。

如您所见,如果使用 Kotlin/Native,您将需要编写更多代码。在这里查看一个完整的示例。


结论

对于 Lambda 函数,您可能还不应该查看 Kotlin/JS 和 Kotlin/Native。

与 JavaScript 和 TypeScript 相比,Kotlin/JS 几乎什么都没有,但需要更多的代码行才能实现相同的结果。面对 JS 固有的动态性会带来一些痛苦,Kotlin/JS 互操作恕我直言不如 Kotlin/JVM。构建更加复杂,并且需要您配置 Gradle 和 NPM 以协同工作(而 JS/TS 只需要 NPM,而 Kotlin/JVM 只需要 Gradle)。

Kotlin/Native 要求您编写更多代码来处理事件。此外,您将无法轻松使用任何 AWS 开发工具包:JVM 库不适用于 Kotlin/Native(尽管您可能会使用比 JVM 低得多的 C/C++ 开发工具包)。构建也更复杂。

如果您有兴趣比较 AWS Lambda 的不同语言/运行时,请查看我在上面多次链接的这个repo。它在 Java、Kotlin/JVM、Kotlin/JS、Kotlin/Native、JS、Ruby、Python 和 Bash 中实现了 Lambda。要阅读有关适用于 AWS Lambdas 的 Kotlin/Native 的更多信息,请访问此处。文章还对不同语言的函数速度进行了对比。域名注册地址:

  1. Kotlin/Native 的性能不是很好。冷启动的 JVM 功能仍然更好。
  2. 如果您正在寻找速度,Golang 可能是 Lambda 函数的最佳选择。
  3. 预热的 JVM(Java 和 Kotlin)函数性能非常好。
  4. Kotlin/JS 提供良好的冷启动时间,但预热的脚本函数让位给 Golang 和 JVM。