Skip to content

Commit 216d625

Browse files
authored
Merge pull request #17 from toydestroyer/ruby-demo
Add Ruby Demo
2 parents e3dbd30 + 75aaf1d commit 216d625

File tree

9 files changed

+248
-3
lines changed

9 files changed

+248
-3
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@ If the runtime or an extension does not respond to the Shutdown event within the
1313

1414
## Demos
1515

16-
This repo includes four examples. Please see the details in each demo folder.
16+
This repo includes seven examples. Please see the details in each demo folder.
1717

1818
- [Node.js Demo](nodejs-demo/)
1919
- [Python Demo](python-demo/)
2020
- [Java Demo](java-demo/)
2121
- [C# Demo](csharp-demo/)
2222
- [Rust Demo](rust-demo/)
2323
- [Golang Demo](golang-demo/)
24+
- [Ruby Demo](ruby-demo/)
2425

2526
## Note
2627

27-
Please be aware that this feature does not work on Python 3.8 through 3.11 runtimes. Please use Python 3.12 runtime for this feature.
28-
28+
Please be aware that this feature does not work on Python 3.8 through 3.11 runtimes. Please use Python 3.12 runtime for this feature.

ruby-demo/Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
source "https://rubygems.org"

ruby-demo/README.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Ruby demo
2+
3+
This folder contains a simple Ruby function with CloudWatch Lambda Insight enabled. CloudWatch Lambda Insight is monitoring and troubleshooting solution for serverless application. Its agent is an external extension. Any external extension will work. We use Lambda Insight extension simply because it is readily available.
4+
5+
*It is recommended to use the latest [Lambda Insights extension](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Lambda-Insights-extension-versions.html)*
6+
```yaml
7+
Properties:
8+
Layers:
9+
# Add Lambda Insight Extension: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Lambda-Insights-extension-versions.html
10+
- !Sub "arn:aws:lambda:${AWS::Region}:580247275435:layer:LambdaInsightsExtension-Arm64:20"
11+
Policies:
12+
# Add IAM Permission for Lambda Insight Extension
13+
- CloudWatchLambdaInsightsExecutionRolePolicy
14+
```
15+
16+
In the function, a simple `SIGTERM` signal handler is added. It will be executed when the lambda runtime receives a `SIGTERM` signal. Note that the signal handler is wrapped in a thread to avoid `can't be called from trap context` error when working with IO.
17+
```ruby
18+
def exit_gracefully
19+
puts "[runtime] SIGTERM received"
20+
puts "[runtime] cleaning up"
21+
22+
# perform actual clean up work here.
23+
sleep 0.2
24+
25+
puts "[runtime] exiting"
26+
end
27+
28+
Signal.trap("TERM") do |signal|
29+
Thread.new { exit_gracefully }.join
30+
end
31+
```
32+
33+
Use the following AWS SAM CLI commands to build and deploy this demo.
34+
35+
```bash
36+
sam build --use-container
37+
sam deploy --guided
38+
```
39+
40+
Take note of the output value of `HelloWorldUrl`. Use curl to invoke the url and trigger the lambda function at least once.
41+
42+
```bash
43+
curl "replace this with value of HelloWorldUrl"
44+
```
45+
46+
Wait for serveral minutes, check the function's log messages in CloudWatch. If you see a log line containing "SIGTERM
47+
received", it works!
48+
49+
For example:
50+
![](./docs/images/ruby-2024-09-13.png)
51+
```
52+
2024-09-13T15:07:32.913Z INIT_START Runtime Version: ruby:3.3.v12 Runtime Version ARN: arn:aws:lambda:ap-southeast-1::runtime:c52b006a8662802f4181b489d3c890a707346347109117f99c7095ee3c4b349d
53+
2024-09-13T15:07:32.970Z LOGS Name: cloudwatch_lambda_agent State: Subscribed Types: [Platform]
54+
2024-09-13T15:07:33.194Z EXTENSION Name: cloudwatch_lambda_agent State: Ready Events: [INVOKE, SHUTDOWN]
55+
2024-09-13T15:07:33.198Z START RequestId: 121e234d-bb3f-49a0-b56f-63e4f66c8fcf Version: $LATEST
56+
2024-09-13T15:07:33.205Z END RequestId: 121e234d-bb3f-49a0-b56f-63e4f66c8fcf
57+
2024-09-13T15:07:33.205Z REPORT RequestId: 121e234d-bb3f-49a0-b56f-63e4f66c8fcf Duration: 6.90 ms Billed Duration: 7 ms Memory Size: 10240 MB Max Memory Used: 64 MB Init Duration: 281.37 ms
58+
2024-09-13T15:13:31.761Z [runtime] SIGTERM received
59+
2024-09-13T15:13:31.761Z [runtime] cleaning up
60+
2024-09-13T15:13:31.961Z [runtime] exiting
61+
```
62+
63+
## Tested Runtimes
64+
65+
| language version | Identifier | Operating system | Architectures | Support status |
66+
|------------------------|-------------------------------------------------------|-------------------|------------------|----------------|
67+
| Ruby 3.3 | ruby3.3 | Amazon Linux 2023 | arm64<br/>x86_64 | ✅ Support |
68+
| Ruby 3.2 | ruby3.2 | Amazon Linux 2 | arm64<br/>x86_64 | ✅ Support |
69+
70+
## Reference:
71+
72+
- [Building Lambda functions with Ruby](https://docs.aws.amazon.com/lambda/latest/dg/lambda-ruby.html)
73+
- [AWS SAM Documentation](https://docs.aws.amazon.com/serverless-application-model/)
321 KB
Loading

ruby-demo/events/event.json

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{
2+
"body": "{\"message\": \"hello world\"}",
3+
"resource": "/{proxy+}",
4+
"path": "/path/to/resource",
5+
"httpMethod": "POST",
6+
"isBase64Encoded": false,
7+
"queryStringParameters": {
8+
"foo": "bar"
9+
},
10+
"pathParameters": {
11+
"proxy": "/path/to/resource"
12+
},
13+
"stageVariables": {
14+
"baz": "qux"
15+
},
16+
"headers": {
17+
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
18+
"Accept-Encoding": "gzip, deflate, sdch",
19+
"Accept-Language": "en-US,en;q=0.8",
20+
"Cache-Control": "max-age=0",
21+
"CloudFront-Forwarded-Proto": "https",
22+
"CloudFront-Is-Desktop-Viewer": "true",
23+
"CloudFront-Is-Mobile-Viewer": "false",
24+
"CloudFront-Is-SmartTV-Viewer": "false",
25+
"CloudFront-Is-Tablet-Viewer": "false",
26+
"CloudFront-Viewer-Country": "US",
27+
"Host": "1234567890.execute-api.us-east-1.amazonaws.com",
28+
"Upgrade-Insecure-Requests": "1",
29+
"User-Agent": "Custom User Agent String",
30+
"Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)",
31+
"X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==",
32+
"X-Forwarded-For": "127.0.0.1, 127.0.0.2",
33+
"X-Forwarded-Port": "443",
34+
"X-Forwarded-Proto": "https"
35+
},
36+
"requestContext": {
37+
"accountId": "123456789012",
38+
"resourceId": "123456",
39+
"stage": "prod",
40+
"requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
41+
"requestTime": "09/Apr/2015:12:34:56 +0000",
42+
"requestTimeEpoch": 1428582896000,
43+
"identity": {
44+
"cognitoIdentityPoolId": null,
45+
"accountId": null,
46+
"cognitoIdentityId": null,
47+
"caller": null,
48+
"accessKey": null,
49+
"sourceIp": "127.0.0.1",
50+
"cognitoAuthenticationType": null,
51+
"cognitoAuthenticationProvider": null,
52+
"userArn": null,
53+
"userAgent": "Custom User Agent String",
54+
"user": null
55+
},
56+
"path": "/prod/path/to/resource",
57+
"resourcePath": "/{proxy+}",
58+
"httpMethod": "POST",
59+
"apiId": "1234567890",
60+
"protocol": "HTTP/1.1"
61+
}
62+
}

ruby-demo/hello_world/Gemfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
source "https://rubygems.org"
2+
3+
ruby '~> 3.3'

ruby-demo/hello_world/app.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# frozen_string_literal: true
2+
3+
require "json"
4+
5+
# SIGTERM Handler: https://docs.aws.amazon.com/lambda/latest/operatorguide/static-initialization.html
6+
# Listening for OS signals that can be handled, reference: https://docs.aws.amazon.com/lambda/latest/dg/runtimes-extensions-api.html
7+
# Termination Signals: https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html
8+
def exit_gracefully
9+
puts "[runtime] SIGTERM received"
10+
puts "[runtime] cleaning up"
11+
12+
# perform actual clean up work here.
13+
sleep 0.2
14+
15+
puts "[runtime] exiting"
16+
end
17+
18+
Signal.trap("TERM") do |signal|
19+
Thread.new { exit_gracefully }.join
20+
end
21+
22+
def lambda_handler(event:, context:)
23+
{
24+
statusCode: 200,
25+
body: {
26+
"message" => "hello ruby",
27+
"source ip" => event["requestContext"]["http"]["sourceIp"],
28+
"architecture" => RbConfig::CONFIG["host_cpu"],
29+
"operating system" => RbConfig::CONFIG["host_os"],
30+
"ruby version " => RUBY_VERSION
31+
}.to_json
32+
}
33+
end

ruby-demo/samconfig.toml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# More information about the configuration file can be found here:
2+
# https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html
3+
version = 0.1
4+
5+
[default.global.parameters]
6+
stack_name = "ruby-graceful-shutdown-demo"
7+
8+
[default.build.parameters]
9+
cached = true
10+
parallel = true
11+
# https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-build.html
12+
use_container = true
13+
14+
[default.validate.parameters]
15+
lint = true
16+
17+
[default.deploy.parameters]
18+
capabilities = "CAPABILITY_IAM"
19+
confirm_changeset = true
20+
resolve_s3 = true
21+
22+
[default.package.parameters]
23+
resolve_s3 = true
24+
25+
[default.sync.parameters]
26+
watch = true
27+
28+
[default.local_start_api.parameters]
29+
warm_containers = "EAGER"
30+
31+
[default.local_start_lambda.parameters]
32+
warm_containers = "EAGER"

ruby-demo/template.yaml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
Transform: AWS::Serverless-2016-10-31
3+
Description: >
4+
ruby-graceful-shutdown-demo
5+
6+
Sample SAM Template for ruby-demo
7+
8+
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
9+
Globals:
10+
Function:
11+
Timeout: 3
12+
13+
Resources:
14+
HelloWorldFunction:
15+
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
16+
Properties:
17+
FunctionName: graceful-shutdown-ruby
18+
CodeUri: hello_world/
19+
Handler: app.lambda_handler
20+
Runtime: ruby3.3
21+
Architectures:
22+
- arm64
23+
Layers:
24+
# Add Lambda Insight Extension: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Lambda-Insights-extension-versions.html
25+
- !Sub "arn:aws:lambda:${AWS::Region}:580247275435:layer:LambdaInsightsExtension-Arm64:20"
26+
Policies:
27+
# Add IAM Permission for Lambda Insight Extension
28+
- CloudWatchLambdaInsightsExecutionRolePolicy
29+
FunctionUrlConfig:
30+
AuthType: NONE
31+
32+
Outputs:
33+
HelloWorldUrl:
34+
Description: "Hello World Function URL"
35+
Value: !GetAtt HelloWorldFunctionUrl.FunctionUrl
36+
HelloWorldFunction:
37+
Description: "Hello World Lambda Function ARN"
38+
Value: !GetAtt HelloWorldFunction.Arn
39+
HelloWorldFunctionIamRole:
40+
Description: "Implicit IAM Role created for Hello World function"
41+
Value: !GetAtt HelloWorldFunctionRole.Arn

0 commit comments

Comments
 (0)