You can use this Terraform code to build your environment so that your AWS Lambda function is regularly called by AWS EventBridge's Scheduler feature.


Structure


├── cmd
│   └── greeter
│   └── main.go
├── .gitignore
├── go.mod
├── go.sum
└── terraform
└── development
└── main.tf

main.go


package main

import (
"context"
"os"

"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"golang.org/x/exp/slog"
)

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

func handler(ctx context.Context, event events.CloudWatchEvent) {
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

logger.Info("scheduler is calling", slog.Any("event", event))
}

main.tf


terraform {
required_version = "~> 1.4.4"

required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.41.0"
}

archive = {
source = "hashicorp/archive"
version = "~> 2.3.0"
}

null = {
source = "hashicorp/null"
version = "~> 3.2.1"
}
}
}

provider "aws" {
profile = "development"
region = "eu-west-1"
}

# -- VARS ----------------------------------------------------------------------

locals {
lambda_function_name = "greeter"

go_source_path = "${path.module}/../../cmd/${local.lambda_function_name}/..."
go_binary_path = "${path.module}/../../bin/${local.lambda_function_name}"
go_zip_path = "${path.module}/../../tmp/${local.lambda_function_name}.zip"
}

# -- LAMBDA --------------------------------------------------------------------

resource "null_resource" "lambda_go_binary" {
provisioner "local-exec" {
command = "GOOS=linux GOARCH=amd64 CGO_ENABLED=0 GOFLAGS=-trimpath go build -mod=readonly -ldflags='-s -w' -o ${local.go_binary_path} ${local.go_source_path}"
}
}

data "archive_file" "lambda_go_zip" {
type = "zip"
source_file = local.go_binary_path
output_path = local.go_zip_path

depends_on = [
null_resource.lambda_go_binary,
]
}

resource "aws_lambda_function" "greeter" {
function_name = local.lambda_function_name
handler = local.lambda_function_name
filename = local.go_zip_path
package_type = "Zip"
runtime = "go1.x"
timeout = 30
memory_size = 128

role = aws_iam_role.lambda_executor.arn
source_code_hash = data.archive_file.lambda_go_zip.output_base64sha256

depends_on = [
aws_cloudwatch_log_group.lambda_log_group,
]
}

resource "aws_iam_role" "lambda_executor" {
name = "greeter-lambda-executor"

managed_policy_arns = [aws_iam_policy.lambda_log.arn]

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
},
]
})
}

resource "aws_iam_policy" "lambda_log" {
name = "greeter-lambda-log"

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
]
Effect = "Allow"
Resource = [
"arn:aws:logs:*:*:*",
]
},
]
})
}

resource "aws_cloudwatch_log_group" "lambda_log_group" {
name = "/aws/lambda/${local.lambda_function_name}"
retention_in_days = 5
}

# -- CLOUDWATCH ----------------------------------------------------------------

resource "aws_scheduler_schedule" "schedule" {
name = "greeter-lambda-schedule"

flexible_time_window {
mode = "OFF"
}

schedule_expression = "rate(1 minutes)"

target {
arn = aws_lambda_function.greeter.arn
role_arn = aws_iam_role.schedule_executor.arn
}
}

resource "aws_iam_role" "schedule_executor" {
name = "greeter-lambda-schedule-executor"

managed_policy_arns = [aws_iam_policy.schedule_invoker.arn]

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "scheduler.amazonaws.com"
}
},
]
})
}

resource "aws_iam_policy" "schedule_invoker" {
name = "greeter-lambda-schedule-invoker"

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "lambda:InvokeFunction"
Effect = "Allow"
Resource = aws_lambda_function.greeter.arn
},
]
})
}

.gitignore


.terraform/
terraform.tfstate*

tmp/
bin/

Provision


me:~/aws/terraform/development$ terraform apply \
-replace="null_resource.lambda_go_binary" \
-replace="archive_file.lambda_go_zip" \
-replace="aws_lambda_function.greeter"

CloudWatch log insights


fields @message
| parse @message '"level":"*"' as level
| filter level in ["INFO", "WARN", "ERROR"]
| display level, @message
| sort @timestamp desc
| limit 20


level, @message
INFO, "{""time"":""2023-07-11T19:54:42.096957233Z"",""level"":""INFO"",""msg"":""scheduler is calling"",""event"":{""...""}}"
INFO, "{""time"":""2023-07-11T19:53:42.122494263Z"",""level"":""INFO"",""msg"":""scheduler is calling"",""event"":{""...""}}"