func init() vs func main() для инициализации глобального состояния в обработчиках AWS Lambda
Посмотрите на раздел Использование глобального состояния в официальном обработчике функций AWS Lambda в документе Go https://docs.aws.amazon.com/lambda/latest/dg/golang-handler.html
предлагает инициализировать все глобальное состояние, т.е. любые переменные уровня пакета, которые мы хотим разделить между несколькими лямбда-вызовами, идут сюда.
Насколько я понимаю, эта инициализация выполняется один раз при запуске лямбда-контейнера (то есть при холодном запуске).
У меня вопрос, можно ли сделать то же самое, используя вместо.
Использование в основном делает мой обработчик функцией (
func LambdaHandler
) не подлежит модульному тестированию из-за побочных эффектов от запуска.
Кажется, что перемещение кода в папку решает эту проблему легко.
Есть ли побочные эффекты при использовании
func main()
против
func init()
Пример кода
Использование func init()
package main
import (
"log"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/aws"
)
var invokeCount = 0
var myObjects []*s3.Object
func init() {
svc := s3.New(session.New())
input := &s3.ListObjectsV2Input{
Bucket: aws.String("examplebucket"),
}
result, _ := svc.ListObjectsV2(input)
myObjects = result.Contents
}
func LambdaHandler() (int, error) {
invokeCount = invokeCount + 1
log.Print(myObjects)
return invokeCount, nil
}
func main() {
lambda.Start(LambdaHandler)
}
против
Использование func main()
package main
import (
"log"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/aws"
)
var invokeCount = 0
var myObjects []*s3.Object
func LambdaHandler() (int, error) {
invokeCount = invokeCount + 1
log.Print(myObjects)
return invokeCount, nil
}
func main() {
svc := s3.New(session.New())
input := &s3.ListObjectsV2Input{
Bucket: aws.String("examplebucket"),
}
result, _ := svc.ListObjectsV2(input)
myObjects = result.Contents
lambda.Start(LambdaHandler)
}
1 ответ
Я бы предложил следующее (которое мы успешно используем во многих лямбдах Go).
main.go
[...]
func (h *handler) handleRequest(ctx context.Context) error {
input := h.s3Client.ListObjectsV2Input{
Bucket: aws.String("examplebucket"),
}
[...]
}
type handler struct {
s3Client s3iface.S3API
}
// main is called only once, when the Lambda is initialised (started for the first time). Code in this function should
// primarily be used to create service clients, read environments variables, read configuration from disk etc.
func main() {
h := handler{
s3client: s3.New(session.New()),
}
lambda.Start(h.handleRequest)
}
main_test.go
type ListObjectsV2Mock struct {
s3iface.S3API
output *s3.ListObjectsV2Output
}
func TestHandleRequest(t *testing.T) {
h := handler{
s3Client: &ListObjectsV2Mock{
output: &s3.ListObjectsV2Output{...},
},
}
err := h.HandleRequest(context.TODO())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
Очевидно, что не хватает большого количества кода (импорт, обработка ошибок и т. Д.), Но в этом суть.