使用AWS EventBridge在Golang中手动发送事件给Lambda函数(详细指南)

398 阅读4分钟

多年来,我们一直投入大量的个人时间和精力,与大家分享我们的知识。然而,我们现在需要你的帮助来维持这个博客的运行。你所要做的就是点击网站上的一个广告,否则它将由于托管等费用而不幸被关闭。谢谢你。

在这个例子中,我们将从一个Golang应用程序中触发事件,并在Lambda函数中处理它们。Golang应用程序使用EventBridge服务来发送事件总线事件到已经定义的事件总线。在另一端,事件规则捕获它并转发到Lambda函数进行处理。

注意

  • 你不需要在你的命令和Golang代码中定义一个自定义的事件总线。你可以简单地使用现有的default 事件总线。然而,你必须至少为事件规则定义一个适当的--event-pattern 条目,以实现正确的事件路由。否则,所有的事件可能最终都会流向同一个Lambda函数。为了便于演示,我将会定义一个。

  • 这个例子使用一个Lambda函数来处理所有事件,但如果你想使用多个Lambda函数,请阅读底部的附加信息。这就像一个事件总线对许多Lambda函数一样

创建Lambda函数

这是负责处理事件的:

package main

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

type Image struct {
	Name string `json:"name"`
	URL  string `json:"url"`
}

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

func upload(_ context.Context, event events.CloudWatchEvent) error {
	fmt.Printf("SOURCE: %+v\n", event.Source)
	fmt.Printf("ACTION: %+v\n", event.DetailType)

	var img Image
	if err := json.Unmarshal(event.Detail, &img); err != nil {
		return err
	}

	fmt.Printf("IMAGE: %+v\n", img)

	return nil
}
$ aws --profile localstack --endpoint-url http://localhost:4566 lambda delete-function --function-name hello-lambda

$ GOOS=linux CGO_ENABLED=0 go build -ldflags "-s -w" -o lambda main.go

$ zip lambda.zip lambda

$ aws --profile localstack --endpoint-url http://localhost:4566 lambda create-function --function-name hello-lambda --handler lambda --runtime go1.x --role create-role --zip-file fileb://lambda.zip
$ aws --profile localstack --endpoint-url http://localhost:4566 lambda list-functions
{
    "Functions": [
        {
            "FunctionName": "hello-lambda",
            "FunctionArn": "arn:aws:lambda:eu-west-1:000000000000:function:hello-lambda",
            "Runtime": "go1.x",
            "Role": "create-role",
            "Handler": "lambda",
            "CodeSize": 2379616,
            "Description": "",
            "Timeout": 3,
            "LastModified": "2022-01-01T20:42:09.707+0000",
            "CodeSha256": "UxruqiDEUheisbAIAMkjbIXnpsMao1UomjsWIwic7XM=",
            "Version": "$LATEST",
            "VpcConfig": {},
            "TracingConfig": {
                "Mode": "PassThrough"
            },
            "RevisionId": "f81daa29-8212-44d7-b04c-1504805a5eea",
            "State": "Active",
            "LastUpdateStatus": "Successful",
            "PackageType": "Zip"
        }
    ]
}

创建事件总线

它将发送事件:

$ aws --profile localstack --endpoint-url http://localhost:4566 events create-event-bus --name hello-event-bus
$ aws --profile localstack --endpoint-url http://localhost:4566 events list-event-buses
{
    "EventBuses": [
        {
            "Name": "default",
            "Arn": "arn:aws:events:eu-west-1:000000000000:event-bus/default"
        },
        {
            "Name": "hello-event-bus",
            "Arn": "arn:aws:events:eu-west-1:000000000000:event-bus/hello-event-bus"
        }
    ]
}

创建事件规则

它将捕捉事件并转发给Lambda:

$ aws --profile localstack --endpoint-url http://localhost:4566 events put-rule --name hello-event-rule --event-bus-name hello-event-bus --event-pattern "{}"
$ aws --profile localstack --endpoint-url http://localhost:4566 events list-rules
{
    "Rules": [
        {
            "Name": "hello-event-rule",
            "Arn": "arn:aws:events:eu-west-1:000000000000:rule/hello-event-bus/hello-event-rule",
            "EventPattern": "{}",
            "State": "ENABLED",
            "EventBusName": "hello-event-bus"
        }
    ]
}

创建事件目标

它将Lambda函数与事件规则联系起来:

$ aws --profile localstack --endpoint-url http://localhost:4566 events put-targets --rule hello-event-rule --targets "Id"="1","Arn"="arn:aws:lambda:eu-west-1:000000000000:function:hello-lambda"
$ aws --profile localstack --endpoint-url http://localhost:4566 events list-targets-by-rule --rule hello-event-rule
{
    "Targets": [
        {
            "Id": "1",
            "Arn": "arn:aws:lambda:eu-west-1:000000000000:function:hello-lambda"
        }
    ]
}

进入应用程序

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/eventbridge"
)

type Image struct {
	Name string `json:"name"`
	URL  string `json:"url"`
}

func main() {
	ctx := context.Background()

	ses, err := session.NewSessionWithOptions(session.Options{
		Profile: "localstack",
		Config: aws.Config{
			Region:   aws.String("eu-west-1"),
			Endpoint: aws.String("http://localhost:4566"),
		},
	})
	if err != nil {
		log.Fatalln(err)
	}

	evb := eventbridge.New(ses)

	img := Image{
		Name: "image.png",
		URL:  "https://www.example.com/image.png",
	}

	data, err := json.Marshal(img)
	if err != nil {
		log.Fatalln(err)
	}

	entries := []*eventbridge.PutEventsRequestEntry{{
		Detail:       aws.String(string(data)),
		DetailType:   aws.String("upload"),
		EventBusName: aws.String("hello-event-bus"),
		Source:       aws.String("example.com"),
	}}

	out, err := evb.PutEventsWithContext(ctx, &eventbridge.PutEventsInput{Entries: entries})
	if err != nil {
		log.Fatalln(err)
	}

	fmt.Println(out.GoString())
}

测试

$ go run main.go
{
  Entries: [{
      EventId: "123f7bbf-7a02-45f7-99c2-84ee7f56d25d"
    }],
  FailedEntryCount: 0
}

日志

localstack    | 2022-01-01T21:28:53.262:DEBUG:localstack.services.awslambda.lambda_executors: Lambda arn:aws:lambda:eu-west-1:000000000000:function:hello-lambda result / log output:
localstack    | null
localstack    | > START RequestId: c59d91e9-3b36-1d3e-1422-1526d364b9e4 Version: $LATEST
localstack    | > SOURCE: example.com
localstack    | > ACTION: upload
localstack    | > IMAGE: {Name:image.png URL:https://www.example.com/image.png}
localstack    | > END RequestId: c59d91e9-3b36-1d3e-1422-1526d364b9e4
localstack    | > REPORT RequestId: c59d91e9-3b36-1d3e-1422-1526d364b9e4        Init Duration: 271.71 ms        Duration: 14.91 ms      Billed Duration: 15 ms  Memory Size: 1536 MB    Max Memory Used: 19 MB

多个Lambda函数

为了在一个事件总线上使用多个Lambda函数,你将创建两个Lambda函数、两个事件规则和两个事件目标,而不是一个。事件规则也将在声明中设置--event-pattern 。之后在你的Golang代码中,DetailType 属性将有助于区分事件将被发送到哪个Lambda函数。我将使用一个不同的名字来代替hello-*

$ aws ... lambda create-function --function-name image-lambda-0 ...

$ aws ... lambda create-function --function-name image-lambda-1 ...

事件规则

$ aws ... events put-rule --name image-event-rule-0 ... --event-pattern "{\"source\":[\"inanzzz.com\"],\"detail-type\":[\"image-upload\"]}"

$ aws ... events put-rule --name image-event-rule-1 ... --event-pattern "{\"source\":[\"inanzzz.com\"],\"detail-type\":[\"image-download\"]}"

事件目标

$ aws ... events put-targets --rule image-event-rule-0 --targets "Id"="1","Arn"="arn:aws:lambda:eu-west-1:000000000000:function:image-lambda-0"

$ aws ... events put-targets --rule image-event-rule-1 --targets "Id"="2","Arn"="arn:aws:lambda:eu-west-1:000000000000:function:image-lambda-1"
...
entries := []*eventbridge.PutEventsRequestEntry{{
	Detail:       aws.String(string(data)),
	// DetailType:   aws.String("image-upload"), // Goes to Lambda 0
	// DetailType:   aws.String("image-download"), // Goes to Lambda 1
	Source:       aws.String("inanzzz.com"),
	EventBusName: aws.String("image-event-bus"),
}}
...