-
Notifications
You must be signed in to change notification settings - Fork 929
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Performing initial commit for terraform pattern of delayed-eventbridg…
…e-events
- Loading branch information
Showing
5 changed files
with
416 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# Delayed EventBridge events with EventBridge Scheduler | ||
|
||
This pattern listens for EventBridge events, processes them and creates schedules for every user. 24 hours after user has been created a schedule is run that publishes events directly into EventBridge. The pattern is deployed using Terraform. | ||
|
||
Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/delayed-eventbridge-events-terraform. | ||
|
||
Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example. | ||
|
||
## Requirements | ||
|
||
* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources. | ||
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured | ||
* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) | ||
* [Terraform](https://learn.hashicorp.com/tutorials/terraform/install-cli?in=terraform/aws-get-started) installed | ||
|
||
## Deployment Instructions | ||
|
||
1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository: | ||
``` | ||
git clone https://github.com/aws-samples/serverless-patterns | ||
``` | ||
1. Change directory to the pattern directory: | ||
``` | ||
cd delayed-eventbridge-events-terraform | ||
``` | ||
1. From the command line, initialize Terraform: | ||
``` | ||
terraform init | ||
``` | ||
1. From the commend line, apply the configuration in the main.tf file and follow the prompts: | ||
``` | ||
terraform apply | ||
``` | ||
|
||
## How it works | ||
|
||
We assume we have a business requirement to email a customer 24 hours after they have signed up. | ||
|
||
1. `UserCreated` event is triggered. In this example we assume a `UserCreated` event is triggered into our event bus. | ||
2. EventBridge Rule setup to listen to the `UserCreated` event. | ||
3. Lambda function listens to `UserCreated` event and creates an Amazon EventBridge Schedule for 24 hours in the future (2 mins for development mode). | ||
4. 24 hours pass, and schedule is triggered and raises `UserCreated24HoursAgo` event directly into EventBridge.. | ||
5. Consumers listen for event and process it. An example would be email a welcome message to customers or an offer etc. | ||
|
||
## Testing | ||
|
||
Use the [AWS CLI](https://aws.amazon.com/cli/) to send a test event to EventBridge: | ||
|
||
1. Send an event to EventBridge: | ||
```bash | ||
aws events put-events --entries "Source='myapp.users',DetailType='UserCreated',Detail='{\"id\": \"test-customer-id\", \"firstName\": \"FirstName\", \"lastName\": \"LastName\"}',EventBusName='<custom-event-bus-ARN>'" | ||
``` | ||
|
||
2. Check the CloudWatch metrics of `UserCreatedRule` and `UserCreated24HoursAgoRule` EventBridge rule and `SchedulesForUsers24HoursAfterCreation` EventBridge Scheduler Group. Also, check the CloudWatch Logs of Lambda Functions which are targets of corresponding `UserCreatedRule` and `UserCreated24HoursAgoRule` EventBridge rules. | ||
|
||
## Cleanup | ||
|
||
1. Delete all created resources and follow prompts: | ||
``` | ||
terraform destroy | ||
``` | ||
---- | ||
Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
|
||
SPDX-License-Identifier: MIT-0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
{ | ||
"title": "Delayed EventBridge events with EventBridge Scheduler", | ||
"description": "Setup future EventBridge events with EventBridge Scheduler", | ||
"language": "", | ||
"level": "200", | ||
"framework": "Terraform", | ||
"introBox": { | ||
"headline": "How it works", | ||
"text": [ | ||
"This pattern listens for EventBridge events, processes them and creates schedules for every user. 24 hours after user has been created a schedule is run that publishes events directly into EventBridge." | ||
] | ||
}, | ||
"gitHub": { | ||
"template": { | ||
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/delayed-eventbridge-events-terraform", | ||
"templateURL": "serverless-patterns/delayed-eventbridge-events-terraform", | ||
"projectFolder": "delayed-eventbridge-events-terraform", | ||
"templateFile": "delayed-eventbridge-events-terraform/main.tf" | ||
} | ||
}, | ||
"resources": { | ||
"bullets": [ | ||
{ | ||
"text": "What is Amazon EventBridge Scheduler?", | ||
"link": "https://docs.aws.amazon.com/scheduler/latest/UserGuide/what-is-scheduler.html" | ||
} | ||
] | ||
}, | ||
"deploy": { | ||
"text": [ | ||
"terraform apply" | ||
] | ||
}, | ||
"testing": { | ||
"text": [ | ||
"See the GitHub repo for detailed testing instructions." | ||
] | ||
}, | ||
"cleanup": { | ||
"text": [ | ||
"Delete the stack: <code>terraform destroy</code>." | ||
] | ||
}, | ||
"authors": [ | ||
{ | ||
"name": "Farrukh Jamal", | ||
"image": "https://media.licdn.com/dms/image/C5103AQHH_uSeGxOlZw/profile-displayphoto-shrink_400_400/0/1570698220038?e=1726099200&v=beta&t=7HUDKvPyM5GbBA1eOhVGB9POwFhXC3v87-vrqCIk1d0", | ||
"bio": "Cloud Engineer at AWS based in the Australia.", | ||
"linkedin": "https://www.linkedin.com/in/farrukhjamal/" | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,247 @@ | ||
terraform { | ||
required_providers { | ||
aws = { | ||
source = "hashicorp/aws" | ||
version = ">= 5.57" | ||
} | ||
} | ||
|
||
required_version = ">= 0.14.9" | ||
} | ||
|
||
provider "aws" { | ||
profile = "default" | ||
region = "us-east-1" | ||
} | ||
|
||
# Create a new eventbus for our demo | ||
resource "aws_cloudwatch_event_bus" "custom_event_bus" { | ||
name = "MyCustomBus" | ||
} | ||
|
||
# need to create role and policy for scheduler to put events onto our bus | ||
resource "aws_iam_role" "scheduler_role" { | ||
name = "delayed-eb-events-SchedulerRole" | ||
assume_role_policy = jsonencode({ | ||
Version = "2012-10-17" | ||
Statement = { | ||
Effect = "Allow" | ||
Action = "sts:AssumeRole" | ||
Principal = { | ||
Service = "scheduler.amazonaws.com" | ||
} | ||
} | ||
}) | ||
|
||
inline_policy { | ||
name = "ScheduleToPutEvents" | ||
policy = jsonencode({ | ||
Version = "2012-10-17" | ||
Statement = [ | ||
{ | ||
Effect = "Allow" | ||
Action = [ | ||
"events:PutEvents", | ||
], | ||
Resource = [aws_cloudwatch_event_bus.custom_event_bus.arn] | ||
}, | ||
] | ||
}) | ||
} | ||
} | ||
|
||
# Creating scheduler group | ||
resource "aws_scheduler_schedule_group" "scheduler_schedule_group" { | ||
name = "SchedulesForUsers24HoursAfterCreation" | ||
} | ||
|
||
data "aws_iam_policy" "lambda_basic_execution_role_policy" { | ||
name = "AWSLambdaBasicExecutionRole" | ||
} | ||
|
||
|
||
# Listen to UserCreated and create the schedule | ||
resource "aws_iam_role" "user_created_function_role" { | ||
name = "delayed-eb-events-UserCreatedFunctionRole" | ||
assume_role_policy = jsonencode({ | ||
Version = "2012-10-17" | ||
Statement = { | ||
Effect = "Allow" | ||
Action = "sts:AssumeRole" | ||
Principal = { | ||
Service = "lambda.amazonaws.com" | ||
} | ||
} | ||
}) | ||
|
||
managed_policy_arns = [ | ||
data.aws_iam_policy.lambda_basic_execution_role_policy.arn | ||
] | ||
|
||
inline_policy { | ||
name = "CreateSchedule" | ||
policy = jsonencode({ | ||
Version = "2012-10-17" | ||
Statement = [ | ||
{ | ||
Effect = "Allow" | ||
Action = [ | ||
"scheduler:CreateSchedule", | ||
"iam:PassRole" | ||
], | ||
Resource = ["*"] | ||
}, | ||
] | ||
}) | ||
} | ||
} | ||
|
||
data "archive_file" "process_user_created_function_zip_file" { | ||
type = "zip" | ||
source_file = "${path.module}/src/process-user-created/index.mjs" | ||
output_path = "${path.module}/process_user_created_function_payload.zip" | ||
} | ||
|
||
resource "aws_lambda_function" "process_user_created_lambda" { | ||
filename = data.archive_file.process_user_created_function_zip_file.output_path | ||
function_name = "ProcessUserCreatedFunction" | ||
role = aws_iam_role.user_created_function_role.arn | ||
handler = "index.handler" | ||
|
||
source_code_hash = data.archive_file.process_user_created_function_zip_file.output_base64sha256 | ||
|
||
runtime = "nodejs20.x" | ||
|
||
environment { | ||
variables = { | ||
SCHEDULE_ROLE_ARN = aws_iam_role.scheduler_role.arn, | ||
EVENTBUS_ARN = aws_cloudwatch_event_bus.custom_event_bus.arn | ||
} | ||
} | ||
} | ||
|
||
# EventBridge rule to listen to UserCreated so we can process it and create schedule | ||
resource "aws_cloudwatch_event_rule" "user_created_rule" { | ||
name = "UserCreatedRule" | ||
description = "Listen to UseCreated events" | ||
|
||
event_pattern = jsonencode({ | ||
source = ["myapp.users"], | ||
detail-type = [ | ||
"UserCreated" | ||
] | ||
}) | ||
event_bus_name = aws_cloudwatch_event_bus.custom_event_bus.arn | ||
} | ||
|
||
resource "aws_cloudwatch_event_target" "user_created_rule_target" { | ||
rule = aws_cloudwatch_event_rule.user_created_rule.name | ||
arn = aws_lambda_function.process_user_created_lambda.arn | ||
event_bus_name = aws_cloudwatch_event_bus.custom_event_bus.name | ||
} | ||
|
||
resource "aws_lambda_permission" "allow_eventbridge" { | ||
statement_id = "AllowExecutionFromEventBridge" | ||
action = "lambda:InvokeFunction" | ||
function_name = aws_lambda_function.process_user_created_lambda.function_name | ||
principal = "events.amazonaws.com" | ||
source_arn = aws_cloudwatch_event_rule.user_created_rule.arn | ||
} | ||
|
||
# Function that listens to schedule directly onto EventBridge and "email a customer" as an example | ||
|
||
resource "aws_iam_role" "email_customer_function_role" { | ||
name = "delayed-eb-events-EmailCustomerFunctionRole" | ||
assume_role_policy = jsonencode({ | ||
Version = "2012-10-17" | ||
Statement = { | ||
Effect = "Allow" | ||
Action = "sts:AssumeRole" | ||
Principal = { | ||
Service = "lambda.amazonaws.com" | ||
} | ||
} | ||
}) | ||
|
||
managed_policy_arns = [ | ||
data.aws_iam_policy.lambda_basic_execution_role_policy.arn | ||
] | ||
} | ||
|
||
data "archive_file" "email_customer_function_zip_file" { | ||
type = "zip" | ||
source_file = "${path.module}/src/email-customer/index.mjs" | ||
output_path = "${path.module}/email_customer_function_payload.zip" | ||
} | ||
|
||
resource "aws_lambda_function" "email_customer_lambda" { | ||
filename = data.archive_file.email_customer_function_zip_file.output_path | ||
function_name = "EmailCustomerFunction" | ||
role = aws_iam_role.email_customer_function_role.arn | ||
handler = "index.handler" | ||
|
||
source_code_hash = data.archive_file.email_customer_function_zip_file.output_base64sha256 | ||
|
||
runtime = "nodejs20.x" | ||
} | ||
|
||
# Rule to match schedules for users and attach our email customer lambda | ||
resource "aws_cloudwatch_event_rule" "user_created_24hours_ago_rule" { | ||
name = "UserCreated24HoursAgoRule" | ||
description = "Listen to UseCreated events" | ||
|
||
event_pattern = jsonencode({ | ||
source = ["scheduler.notifications"], | ||
detail-type = [ | ||
"UserCreated24HoursAgo" | ||
] | ||
}) | ||
event_bus_name = aws_cloudwatch_event_bus.custom_event_bus.arn | ||
} | ||
|
||
resource "aws_cloudwatch_event_target" "user_created_24hours_ago_rule_target" { | ||
rule = aws_cloudwatch_event_rule.user_created_24hours_ago_rule.name | ||
arn = aws_lambda_function.email_customer_lambda.arn | ||
event_bus_name = aws_cloudwatch_event_bus.custom_event_bus.name | ||
} | ||
|
||
resource "aws_lambda_permission" "allow_eventbridge_email_customer_lambda" { | ||
statement_id = "AllowExecutionFromEventBridge" | ||
action = "lambda:InvokeFunction" | ||
function_name = aws_lambda_function.email_customer_lambda.function_name | ||
principal = "events.amazonaws.com" | ||
source_arn = aws_cloudwatch_event_rule.user_created_24hours_ago_rule.arn | ||
} | ||
|
||
# Outputs | ||
output "custom_event_bus_arn" { | ||
description = "Custom Event Bus ARN" | ||
value = aws_cloudwatch_event_bus.custom_event_bus.arn | ||
} | ||
|
||
output "user_created_rule_arn" { | ||
description = "UserCreatedRule rule ARN" | ||
value = aws_cloudwatch_event_rule.user_created_rule.arn | ||
} | ||
|
||
output "user_created_24hours_ago_rule_arn" { | ||
description = "UserCreated24HoursAgoRule rule ARN" | ||
value = aws_cloudwatch_event_rule.user_created_24hours_ago_rule.arn | ||
} | ||
|
||
output "scheduler_group_name" { | ||
description = "SchedulesForUsers24HoursAfterCreation scheduler group name" | ||
value = aws_scheduler_schedule_group.scheduler_schedule_group.name | ||
} | ||
|
||
output "process_user_created_lambda_function_log_group" { | ||
description = "ProcessUserCreatedFunction CloudWatch Log Group" | ||
value = "/aws/lambda/${aws_lambda_function.process_user_created_lambda.function_name}" | ||
} | ||
|
||
output "email_customer_lambda_function_log_group" { | ||
description = "EmailCustomerFunction CloudWatch Log Group" | ||
value = "/aws/lambda/${aws_lambda_function.email_customer_lambda.function_name}" | ||
} | ||
|
||
|
12 changes: 12 additions & 0 deletions
12
delayed-eventbridge-events-terraform/src/email-customer/index.mjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
export const handler = async (event) => { | ||
|
||
// Received EventBridge Scheduler schedule event | ||
console.log('Received event:', JSON.stringify(event, null, 2)); | ||
|
||
|
||
/** | ||
* Example of a consumer for the UserCreated24HoursAgo event, if you wanted to email them you could put your email code here | ||
*/ | ||
|
||
console.log('Email the customer 24 hours ago after they were created.') | ||
}; |
Oops, something went wrong.