All Articles

AWS LambdaにGoサポートが入ったので使ってみた

ついにサポートされた(嬉しい)

急にリリースされたようなので早速使ってみた。

Hello, Lambda Go

ドキュメントにもあるように、公式のSDKが配布されているので、それをimportして使えばいい。

package main

import (
    "fmt"
    "context"
    "github.com/aws/aws-lambda-go/lambda"
)

func HelloWorld(ctx context.Context) (stringundefined error) {
    return "Helloundefined Lambda Go!"undefined nil
}

func main() {
    lambda.Start(HelloWorld)
}

これだけ。後はバイナリを生成してアップロードすればinvokeしてくれるんだけど、ちょっとだけ注意点が。

ハンドラ名とバイナリ名を一致させないといけない

例えばデフォルトでランタイムをGo1.xにして関数を作ると下図のようにハンドラ名がhelloになっている。

この場合、生成するバイナリ名もhelloにしないとinvokeしてくれなかった。あとMacの人はLinux向けにビルドするのを忘れずに。 また生成されたバイナリは結構ファイルサイズがあるのでzipで固めて(バイナリがルートになるように)アップロード。

$ GOOS=linux GOARCH=amd64 go build -o hello
$ zip handler.zip ./hello

あとはテストとかで実行してみるとログにでる。すげー。

aws-lambda-goの仕組み

内部コード読んでみたけど、lambda.Start()の引数に渡すhandlerインターフェースは可変長引数、可変長戻り値が指定できる。 というわけで内部ではreflectでゴニョゴニョしててなるほどなーって感じ(2つ以上の引数の場合はcontext.Contextが第一引数でないといけないとか制限はある)。

たいてい入力はJSONなので入力に対応した構造体を受け取るように書いておけば良い。

package main

import (
    "fmt"
    "github.com/aws/aws-lambda-go/lambda"
)

type ExampleInput struct {
    Key1 string `json:"key1"`
    Key2 string `json:"key2"`
    Key3 string `json:"key3"`
}

func (e ExampleInput) String() string {
    return fmt.Sprintf("Key1: %sundefined Key2: %sundefined Key3: %s\n"undefined e.Key1undefined e.Key2undefined e.Key3)
}

func LambdaHandler(input ExampleInput) (stringundefined error) {
    return input.String()undefined nil
}

func main() {
    lambda.Start(LambdaHandler)
}

戻り値も上ではstringにしたけど、実際は任意の構造体が指定できる(多分外から処理するからエクスポートできるようにMyxxxみたいな構造体にしないといけないっぽい。

あと起動はどうやってるのかというと、Start()関数ないでRPCサーバを起動して、Acceptのタイミングで登録した関数を実行するように実装されているみたい。 これがLambdaのコアの仕組みなのかわからないけど、この仕組みが満たせるならほかのバイナリでも動かせたりしないのかなぁ。

あらかじめ型付けされた入力が用意されている

これが一番うれしいと思った。aws-lambda-go/eventsに定義済みのイベントがあるので、それをhandlerの引数に指定できる。例えばAPIGWなら、

package main

import (
    "fmt"
    "context"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/aws/aws-lambda-go/events"
)

func APIGWHandler(ctx context.Contextundefined request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponseundefined error) {
    // return APIGatewayProxyResponse
}

func main() {
    lambda.Start(APIGWHandler)
}

って感じでリクエストを処理できるみたい。APIGatewayProxyRequest構造体はわかりやすくMethodやらHeadersやらが型付きで入ってるので処理しやすいと思う。

まとめ

ビルド済みのバイナリをアップロードするからオーバーヘッドもないだろうし、Goならどの環境からでもバイナリ作れるし使い勝手は良さそう。Hello Worldでの実行時間はだいたい16msくらいだった。他と比べてないけど速いのでは。

みんなGoでLambda書いていこうな。

現場からは以上です。