01/01/2022 - AWS, GO
In this example we are going to fire events from a Golang application and process them in a Lambda function. Golang application uses the EventBridge service to send an Event Bus event to a already defined Event Bus. On the other end, the Event Rule catches it and forwards to the Lambda function for processing.
default
Event Bus. However, you must at least define a proper --event-pattern
entry for the Event Rule for correct event routing. Otherwise all events might end up going to the same Lambda function. For the sake of demonstration, I will be defining one.This is responsible for processing the event.
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"
}
]
}
It will send events.
$ 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"
}
]
}
It will catch events and forward to 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"
}
]
}
This links Lambda function with the event rule.
$ 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
In order to use multiple Lambda functions with a single Event Bus, you will create two Lambda functions, two Event Rules and two Event Targets instead of one. The Event Rule will also have the --event-pattern
set in declaration. Afterwards in your Golang code the DetailType
property will help differentiate which Lambda function the event will be sent to. I am going to use a different name instead of 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"),
}}
...