Skip to content

Commit 1ffc4d4

Browse files
authored
Merge pull request #11 from thinktik/golang-dev
2 parents 4918837 + d1af26f commit 1ffc4d4

File tree

9 files changed

+304
-0
lines changed

9 files changed

+304
-0
lines changed

golang-demo/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.aws-sam
2+
.idea

golang-demo/README.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# golang graceful shutdown demo
2+
3+
This folder contains a simple golang function
4+
with [CloudWatch Lambda Insight](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-insights.html) enabled.
5+
CloudWatch Lambda Insight is
6+
monitoring and troubleshooting solution for serverless application. Its agent is an external extension. Any external
7+
extension will work. We use Lambda Insight extension simply because it is readily available.
8+
9+
*It is recommended to use the
10+
latest [Lambda Insights extension](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Lambda-Insights-extension-versions.html)*
11+
12+
```yaml
13+
Layers:
14+
# Add Lambda Insight Extension: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Lambda-Insights-extension-versions.html
15+
- !Sub "arn:aws:lambda:${AWS::Region}:580247275435:layer:LambdaInsightsExtension-Arm64:5"
16+
Policies:
17+
# Add IAM Permission for Lambda Insight Extension
18+
- CloudWatchLambdaInsightsExecutionRolePolicy
19+
```
20+
21+
In the function, a simple signal handler is added. It will be executed when the lambda runtime receives a
22+
`SIGTERM` signal or other signal. You can also add more signal types yourself.
23+
24+
```go
25+
// Static initialization
26+
// SIGTERM Handler: https://docs.aws.amazon.com/lambda/latest/operatorguide/static-initialization.html
27+
func init() {
28+
// Create a chan to receive os signal
29+
var c = make(chan os.Signal)
30+
// Listening for os signals that can be handled,reference: https://docs.aws.amazon.com/lambda/latest/dg/runtimes-extensions-api.html
31+
// Termination Signals: https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html
32+
signal.Notify(c, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGHUP)
33+
// do something when os signal received
34+
go func() {
35+
for s := range c {
36+
switch s {
37+
// if lambda runtime received SIGTERM signal,perform actual clean up work here.
38+
case syscall.SIGTERM:
39+
fmt.Println("[runtime] SIGTERM received")
40+
fmt.Println("[runtime] Graceful shutdown in progress ...")
41+
fmt.Println("[runtime] Graceful shutdown completed")
42+
os.Exit(0)
43+
// else if lambda runtime received other signal
44+
default:
45+
fmt.Println("[runtime] Other signal received")
46+
fmt.Println("[runtime] Graceful shutdown in progress ...")
47+
fmt.Println("[runtime] Graceful shutdown completed")
48+
os.Exit(0)
49+
}
50+
}
51+
}()
52+
}
53+
```
54+
55+
Use the following AWS SAM CLI commands to build and deploy this demo.
56+
57+
```bash
58+
sam build
59+
sam deploy
60+
```
61+
62+
Take note of the output value of `GoHelloWorldApi`. Use curl to invoke the api and trigger the lambda function at least once.
63+
64+
```bash
65+
curl "replace this with value of GoHelloWorldApi"
66+
```
67+
68+
Waite for several minutes, check the function's log messages in CloudWatch. If you see a log line containing "SIGTERM
69+
received", it works!
70+
71+
for example:
72+
![](./docs/images/golang-2023-12-15.png)
73+
```text
74+
2023-12-15T14:03:59.046+08:00 INIT_START Runtime Version: provided:al2023.v10 Runtime Version ARN: arn:aws:lambda:us-east-1::runtime:389fcaae1b213b40d38ed791dfb615af1a71a32d6996ff7c4afdde3d5af4b6f2
75+
2023-12-15T14:03:59.104+08:00 LOGS Name: cloudwatch_lambda_agent State: Subscribed Types: [Platform]
76+
2023-12-15T14:03:59.173+08:00 EXTENSION Name: cloudwatch_lambda_agent State: Ready Events: [INVOKE, SHUTDOWN]
77+
2023-12-15T14:03:59.175+08:00 START RequestId: 90d93089-6e10-45f2-81f2-3a640945976b Version: $LATEST
78+
2023-12-15T14:03:59.230+08:00 END RequestId: 90d93089-6e10-45f2-81f2-3a640945976b
79+
2023-12-15T14:03:59.230+08:00 REPORT RequestId: 90d93089-6e10-45f2-81f2-3a640945976b Duration: 55.01 ms Billed Duration: 183 ms Memory Size: 128 MB Max Memory Used: 31 MB Init Duration: 127.75 ms
80+
2023-12-15T14:04:07.275+08:00 START RequestId: 89827818-1fdf-4626-a0eb-4cb509171c29 Version: $LATEST
81+
2023-12-15T14:04:07.330+08:00 END RequestId: 89827818-1fdf-4626-a0eb-4cb509171c29
82+
2023-12-15T14:04:07.330+08:00 REPORT RequestId: 89827818-1fdf-4626-a0eb-4cb509171c29 Duration: 55.80 ms Billed Duration: 56 ms Memory Size: 128 MB Max Memory Used: 31 MB
83+
2023-12-15T14:09:35.620+08:00 [runtime] SIGTERM received
84+
2023-12-15T14:09:35.620+08:00 [runtime] Graceful shutdown in progress ...
85+
2023-12-15T14:09:35.620+08:00 [runtime] Graceful shutdown completed
86+
```
87+
88+
## Tested Runtimes
89+
90+
| language version | Identifier | Operating system | Architectures | Support status |
91+
|-----------------------------|-----------------|-------------------|------------------|----------------|
92+
| go 1.x<br/>(1.19,1.20,1.21) | provided.al2023 | Amazon Linux 2023 | arm64<br/>x86_64 | ✅Support |
93+
| go 1.x<br/>(1.19,1.20,1.21) | provided.al2 | Amazon Linux 2 | arm64<br/>x86_64 | ✅Support |
94+
95+
## Reference:
96+
97+
- [Building Lambda functions with Go](https://docs.aws.amazon.com/lambda/latest/dg/lambda-golang.html)
98+
- [AWS SAM Documentation](https://docs.aws.amazon.com/serverless-application-model/)
420 KB
Loading

golang-demo/events/event.json

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{
2+
"body": "{\"message\": \"hello world\"}",
3+
"resource": "/hello",
4+
"path": "/hello",
5+
"httpMethod": "GET",
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/hello",
57+
"resourcePath": "/hello",
58+
"httpMethod": "POST",
59+
"apiId": "1234567890",
60+
"protocol": "HTTP/1.1"
61+
}
62+
}
63+

golang-demo/hello-world/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
build-HelloWorldFunction:
2+
# https://go.dev/doc/install/source#environment
3+
#GOOS=linux GOARCH=amd64 go build -o bootstrap
4+
GOOS=linux go build -o bootstrap
5+
cp ./bootstrap $(ARTIFACTS_DIR)/.

golang-demo/hello-world/go.mod

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
require github.com/aws/aws-lambda-go v1.36.1
2+
3+
replace gopkg.in/yaml.v2 => gopkg.in/yaml.v2 v2.2.8
4+
5+
module hello-world
6+
7+
go 1.21

golang-demo/hello-world/go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
github.com/aws/aws-lambda-go v1.36.1 h1:CJxGkL9uKszIASRDxzcOcLX6juzTLoTKtCIgUGcTjTU=
2+
github.com/aws/aws-lambda-go v1.36.1/go.mod h1:jwFe2KmMsHmffA1X2R09hH6lFzJQxzI8qK17ewzbQMM=
3+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
4+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
6+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
7+
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
8+
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
9+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
10+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

golang-demo/hello-world/main.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"github.com/aws/aws-lambda-go/events"
8+
"github.com/aws/aws-lambda-go/lambda"
9+
"os"
10+
"os/signal"
11+
"runtime"
12+
"syscall"
13+
)
14+
15+
// Static initialization
16+
// SIGTERM Handler: https://docs.aws.amazon.com/lambda/latest/operatorguide/static-initialization.html
17+
func init() {
18+
// Create a chan to receive os signal
19+
var c = make(chan os.Signal)
20+
// Listening for os signals that can be handled,reference: https://docs.aws.amazon.com/lambda/latest/dg/runtimes-extensions-api.html
21+
// Termination Signals: https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html
22+
signal.Notify(c, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGHUP)
23+
// do something when os signal received
24+
go func() {
25+
for s := range c {
26+
switch s {
27+
// if lambda runtime received SIGTERM signal,perform actual clean up work here.
28+
case syscall.SIGTERM:
29+
fmt.Println("[runtime] SIGTERM received")
30+
fmt.Println("[runtime] Graceful shutdown in progress ...")
31+
fmt.Println("[runtime] Graceful shutdown completed")
32+
os.Exit(0)
33+
// else if lambda runtime received other signal
34+
default:
35+
fmt.Println("[runtime] Other signal received")
36+
fmt.Println("[runtime] Graceful shutdown in progress ...")
37+
fmt.Println("[runtime] Graceful shutdown completed")
38+
os.Exit(0)
39+
}
40+
}
41+
}()
42+
}
43+
44+
// https://docs.aws.amazon.com/lambda/latest/dg/golang-handler.html
45+
func handler(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
46+
bodyContent := map[string]string{
47+
"message": "hello golang",
48+
"source ip": request.RequestContext.Identity.SourceIP,
49+
"architecture": runtime.GOARCH,
50+
"operating system": runtime.GOOS,
51+
"go version": runtime.Version(),
52+
}
53+
54+
s, _ := json.Marshal(bodyContent)
55+
greeting := fmt.Sprintf(string(s))
56+
57+
return events.APIGatewayProxyResponse{
58+
Body: greeting,
59+
StatusCode: 200,
60+
}, nil
61+
}
62+
63+
func main() {
64+
lambda.Start(handler)
65+
}

golang-demo/template.yaml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
Transform: AWS::Serverless-2016-10-31
3+
Description: >
4+
golang-graceful-shutdown-demo
5+
6+
lambda graceful shutdown-demo(golang edition)
7+
8+
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
9+
Globals:
10+
Function:
11+
Timeout: 5
12+
MemorySize: 128
13+
14+
Resources:
15+
HelloWorldFunction:
16+
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
17+
Properties:
18+
FunctionName: graceful-shutdown-golang
19+
CodeUri: hello-world/
20+
Handler: hello-world
21+
Runtime: provided.al2023
22+
Architectures:
23+
- arm64
24+
Layers:
25+
# Add Lambda Insight Extension: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Lambda-Insights-extension-versions.html
26+
- !Sub "arn:aws:lambda:${AWS::Region}:580247275435:layer:LambdaInsightsExtension-Arm64:5"
27+
Policies:
28+
# Add IAM Permission for Lambda Insight Extension
29+
- CloudWatchLambdaInsightsExecutionRolePolicy
30+
Events:
31+
CatchAll:
32+
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
33+
Properties:
34+
Path: /hello
35+
Method: GET
36+
Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object
37+
Variables:
38+
projectName: golangGracefulShutdown
39+
Metadata:
40+
BuildMethod: makefile
41+
42+
Outputs:
43+
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
44+
# Find out more about other implicit resources you can reference within SAM
45+
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
46+
GoHelloWorldAPI:
47+
Description: "API Gateway endpoint URL for Prod environment for First Function"
48+
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
49+
GoHelloWorldFunction:
50+
Description: "First Lambda Function ARN"
51+
Value: !GetAtt HelloWorldFunction.Arn
52+
GoHelloWorldFunctionIamRole:
53+
Description: "Implicit IAM Role created for Hello World function"
54+
Value: !GetAtt HelloWorldFunctionRole.Arn

0 commit comments

Comments
 (0)