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.


Note




Create Lambda function


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"
}
]
}

Create Event Bus


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"
}
]
}

Create Event Rule


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"
}
]
}

Create Event Target


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"
}
]
}

Go application


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())
}

Test


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

Logs


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

Multiple Lambda function


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-*.


Lambda function


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

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

Event Rule


$ 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\"]}"

Event Target


$ 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"

Golang


...
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"),
}}
...