Skip to content

Commit d722be7

Browse files
MEPalmajoe4dev
authored andcommitted
python samples
1 parent de13f51 commit d722be7

File tree

13 files changed

+490
-0
lines changed

13 files changed

+490
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"name": "Python: Remote Attach",
6+
"type": "debugpy",
7+
"request": "attach",
8+
"connect": {
9+
"host": "localhost",
10+
"port": 19891
11+
},
12+
"pathMappings": [
13+
{
14+
"localRoot": "${workspaceFolder}",
15+
"remoteRoot": "."
16+
}
17+
]
18+
}
19+
]
20+
}
21+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export AWS_ACCESS_KEY_ID ?= test
2+
export AWS_SECRET_ACCESS_KEY ?= test
3+
export AWS_DEFAULT_REGION = us-east-1
4+
VENV_DIR ?= .venv
5+
6+
usage: ## Show this help
7+
@fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//'
8+
9+
install: ## Install dependencies
10+
@which awslocal || pip install awscli-local
11+
test -e $(VENV_DIR) || virtualenv $(VENV_DIR)
12+
. $(VENV_DIR)/bin/activate; pip install debugpy
13+
14+
run: ## Deploy and invoke the Lambda container locally
15+
echo "Deploying Lambda locally"; \
16+
./run.sh; \
17+
echo "Done - test successfully finished."
18+
19+
.PHONY: usage install run
20+
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# LocalStack Demo: Enable Lambda Debug Mode to Automatically Raise Execution Timeouts
2+
3+
A simple demo application showcasing how to debug Python Lambdas locally with Lambda Debug Mode.
4+
The demo deploys a Lambda function with a one-second timeout, which is automatically lifted when running LocalStack with Lambda Debug Mode enabled.
5+
6+
## Prerequisites
7+
8+
* LocalStack
9+
* Docker
10+
* `make`
11+
* [`awslocal`](https://github.com/localstack/awscli-local)
12+
13+
## Installing
14+
15+
To install the dependencies:
16+
```
17+
make install
18+
```
19+
20+
## Starting Up
21+
22+
Make sure that LocalStack is started with the following configuration:
23+
```
24+
LAMBDA_DEBUG_MODE=1 \
25+
LAMBDA_DEBUG_MODE_CONFIG_PATH=path/to/lambda_debug_mode_config.yaml \
26+
localstack start
27+
```
28+
29+
Lambda Debug Mode is enabled through the config option `LAMBDA_DEBUG_MODE=1`.
30+
31+
The config option `LAMBDA_DEBUG_MODE_CONFIG_PATH` should point to the provided `yaml` config file for Lambda Debug Mode `lambda_debug_mode_config.yaml`.
32+
The config file contains instructions for Lambda Debug Mode to debug the Lambda function `arn:aws:lambda:us-east-1:000000000000:function:function-one` on port `19891`.
33+
34+
35+
## Running the Sample
36+
37+
The project ships with a Visual Studio Code debug launch config (see `.vscode/launch.json`). This configuration can be used to attach to the code in the Lambda function while it is executing.
38+
39+
The following command used to first install the dependencies (e.g., `debugpy`), then deploy, and finally invoke the Lambda locally:
40+
41+
```
42+
make run
43+
```
44+
45+
### Attaching the VSCode Debugger
46+
47+
After the Lambda function is invoked you can switch to Visual Studio Code, set a breakpoint in the Lambda handler, and run the preconfigured remote debugger.
48+
LocalStack will automatically waive the set one second timeout for the Lambda function, giving you ample time to connect the debugger and debug the logic in the function.
49+
50+
### Quick Dev Loop with Lambda Code Mounting
51+
52+
Note that, since the Lambda code is mounted from your local filesystem into the Lambda container (by means of `hot-reload` as special bucket name in `run.sh`),
53+
all changes are immediately reflected. For example, you could change the implementation of the handler as follows:
54+
```
55+
def handler(event, context):
56+
"""Lambda handler that will get invoked by the LocalStack runtime"""
57+
58+
# Wait for the debugger to get attached.
59+
wait_for_debug_client()
60+
61+
# Print the incoming invocation event.
62+
print(event)
63+
64+
# Additional line added below:
65+
print("!! Additional log output !!")
66+
67+
# Return the incomeing invocation evant.
68+
return event
69+
```
70+
and then upon next invocation of the Lambda, the additional print output will immediately appear in the Lambda logs.
71+
This allows for a quick dev/debug loop, without the need to redeploy the Lambda after the handler is changed!
72+
73+
## License
74+
75+
The code in this sample is available under the Apache 2.0 license.
76+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
def handler(event, context):
2+
"""Lambda handler that will get invoked by the LocalStack runtime"""
3+
4+
# Wait for the debugger to get attached.
5+
wait_for_debug_client()
6+
7+
# Print the incoming invocation event.
8+
print(event)
9+
10+
# Return the incomeing invocation evant.
11+
return event
12+
13+
14+
def wait_for_debug_client(timeout=15):
15+
"""Utility function to enable debugging with Visual Studio Code"""
16+
import time, threading
17+
import sys, glob
18+
sys.path.append(glob.glob(".venv/lib/python*/site-packages")[0])
19+
import debugpy
20+
21+
debugpy.listen(("0.0.0.0", 19891))
22+
class T(threading.Thread):
23+
daemon = True
24+
def run(self):
25+
time.sleep(timeout)
26+
print("Canceling debug wait task ...")
27+
debugpy.wait_for_client.cancel()
28+
T().start()
29+
print("Waiting for client to attach debugger ...")
30+
debugpy.wait_for_client()
31+
32+
33+
if __name__ == "__main__":
34+
handler({}, {})
35+
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
functions:
2+
arn:aws:lambda:us-east-1:000000000000:function:function-one:
3+
debug-port: 19891
4+
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/bin/bash
2+
#
3+
# Set the name of the Lambda function.
4+
FUNCTION_NAME="function-one"
5+
6+
# Create the Lambda function 'function-one' through hot-reload with one second timeout.
7+
echo "Creating Lambda function $FUNCTION_NAME through hot-reload with one second timeout."
8+
awslocal lambda create-function \
9+
--function-name "$FUNCTION_NAME"\
10+
--timeout 1 \
11+
--code "S3Bucket=hot-reload,S3Key=$(pwd)/" \
12+
--handler handler.handler \
13+
--role arn:aws:iam::000000000000:role/test-role \
14+
--runtime python3.9
15+
16+
# Function to check the status of the Lambda function.
17+
check_lambda_status() {
18+
status=$(awslocal lambda get-function --function-name "$FUNCTION_NAME" 2>&1)
19+
# Check if "Active" is in the response
20+
if echo "$status" | grep -q "Active"; then
21+
return 0
22+
fi
23+
return 1
24+
}
25+
26+
# Wait until the Lambda function is active
27+
echo "Waiting for Lambda function to become active..."
28+
while true; do
29+
if check_lambda_status; then
30+
echo "Lambda function is active."
31+
break
32+
else
33+
echo "Lambda function is still pending. Waiting..."
34+
sleep 1
35+
fi
36+
done
37+
38+
# Invoke the Lambda function.
39+
echo "Invoking the Lambda function."
40+
awslocal lambda invoke \
41+
--function-name function-one \
42+
test.lambda.log \
43+
--payload '{"message": "Testing Lambda Debug Mode lifting the 1-second timeout for function-one."}'
44+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"name": "Python: Remote Attach to function_one",
6+
"type": "debugpy",
7+
"request": "attach",
8+
"connect": {
9+
"host": "localhost",
10+
"port": 19891
11+
},
12+
"pathMappings": [
13+
{
14+
"localRoot": "${workspaceFolder}",
15+
"remoteRoot": "."
16+
}
17+
]
18+
},
19+
{
20+
"name": "Python: Remote Attach to function_two",
21+
"type": "debugpy",
22+
"request": "attach",
23+
"connect": {
24+
"host": "localhost",
25+
"port": 19892
26+
},
27+
"pathMappings": [
28+
{
29+
"localRoot": "${workspaceFolder}",
30+
"remoteRoot": "."
31+
}
32+
]
33+
}
34+
]
35+
}
36+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export AWS_ACCESS_KEY_ID ?= test
2+
export AWS_SECRET_ACCESS_KEY ?= test
3+
export AWS_DEFAULT_REGION = us-east-1
4+
VENV_DIR ?= .venv
5+
6+
usage: ## Show this help
7+
@fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//'
8+
9+
install: ## Install dependencies
10+
@which awslocal || pip install awscli-local
11+
test -e $(VENV_DIR) || virtualenv $(VENV_DIR)
12+
. $(VENV_DIR)/bin/activate; pip install debugpy
13+
14+
run: ## Deploy and invoke the Lambda container locally
15+
echo "Deploying Lambda locally"; \
16+
./run.sh; \
17+
echo "Done - test successfully finished."
18+
19+
.PHONY: usage install run
20+
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# LocalStack Demo: Enable Lambda Debug Mode to Automatically Raise Execution Timeouts
2+
3+
A simple demo application showcasing how to debug multiple Python Lambdas locally with Lambda Debug Mode.
4+
The demo deploys two Lambda function with a one-second timeout, Lambda Debug Mode is then used to automatically lift the execution timeouts
5+
and configure the Docker container to open specific debug ports for the two lambda functions.
6+
7+
## Prerequisites
8+
9+
* LocalStack
10+
* Docker
11+
* `make`
12+
* [`awslocal`](https://github.com/localstack/awscli-local)
13+
14+
## Installing
15+
16+
To install the dependencies:
17+
```
18+
make install
19+
```
20+
21+
## Starting Up
22+
23+
Make sure that LocalStack is started with the following configuration:
24+
```
25+
LAMBDA_DEBUG_MODE=1 \
26+
LAMBDA_DEBUG_MODE_CONFIG_PATH=path/to/lambda_debug_mode_config.yaml \
27+
localstack start
28+
```
29+
30+
Lambda Debug Mode is enabled through the config option `LAMBDA_DEBUG_MODE=1`.
31+
32+
The config option `LAMBDA_DEBUG_MODE_CONFIG_PATH` should point to the provided `yaml` config file for Lambda Debug Mode `lambda_debug_mode_config.yaml`.
33+
The config file contains instructions for Lambda Debug Mode to debug
34+
Lambda function `arn:aws:lambda:us-east-1:000000000000:function:function-one` on port `19891` and
35+
Lambda function `arn:aws:lambda:us-east-1:000000000000:function:function-two` on port `19892`.
36+
The two lambda functions configure `debugpy` to listen for debug connections on the corresponding ports.
37+
38+
39+
## Running the Sample
40+
41+
The project ships with a Visual Studio Code debug launch config (see `.vscode/launch.json`). This configuration can be used to attach to the code in the Lambda function while it is executing.
42+
43+
The following command used to first install the dependencies (e.g., `debugpy`), then deploy, and finally invoke the Lambda locally:
44+
45+
```
46+
make run
47+
```
48+
49+
### Attaching the VSCode Debugger
50+
51+
After the Lambda function is invoked you can switch to Visual Studio Code, set a breakpoint in the Lambda handler, and run the preconfigured remote debuggers.
52+
You will find that you can run the two preconfigured remote debuggers at the same time and simultaneously debug both Lambda functions.
53+
LocalStack will automatically waive the set one second timeout for the Lambda function, giving you ample time to connect the debugger and debug the logic in the function.
54+
55+
### Quick Dev Loop with Lambda Code Mounting
56+
57+
Note that, since the Lambda code is mounted from your local filesystem into the Lambda container (by means of `hot-reload` as special bucket name in `run.sh`),
58+
all changes are immediately reflected. For example, you could change the implementation of the handler for `function_one` as follows:
59+
```
60+
def handler(event, context):
61+
"""Lambda handler that will get invoked by the LocalStack runtime"""
62+
63+
# Wait for the debugger to get attached.
64+
wait_for_debug_client()
65+
66+
# Print a message to log that this the handler of handler_function_one.py file.
67+
print("The handler of handler_function_one.py is evaluating.")
68+
69+
# Print the incoming invocation event.
70+
print(event)
71+
72+
# Additional line added below:
73+
print("!! Additional log output !!")
74+
75+
# Return the incomeing invocation evant.
76+
return event
77+
```
78+
79+
and then upon next invocation of the Lambda, the additional print output will immediately appear in the Lambda logs.
80+
This allows for a quick dev/debug loop, without the need to redeploy the Lambda after the handler is changed!
81+
82+
## License
83+
84+
The code in this sample is available under the Apache 2.0 license.
85+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
def handler(event, context):
2+
"""Lambda handler that will get invoked by the LocalStack runtime"""
3+
4+
# Wait for the debugger to get attached.
5+
wait_for_debug_client()
6+
7+
# Print a message to log that this the handler of handler_function_one.py file.
8+
print("The handler of handler_function_one.py is evaluating.")
9+
10+
# Print the incoming invocation event.
11+
print(event)
12+
13+
# Return the incomeing invocation evant.
14+
return event
15+
16+
17+
def wait_for_debug_client(timeout=15):
18+
"""Utility function to enable debugging with Visual Studio Code"""
19+
import time, threading
20+
import sys, glob
21+
sys.path.append(glob.glob(".venv/lib/python*/site-packages")[0])
22+
import debugpy
23+
24+
debugpy.listen(("0.0.0.0", 19891))
25+
class T(threading.Thread):
26+
daemon = True
27+
def run(self):
28+
time.sleep(timeout)
29+
print("Canceling debug wait task ...")
30+
debugpy.wait_for_client.cancel()
31+
T().start()
32+
print("Waiting for client to attach debugger ...")
33+
debugpy.wait_for_client()
34+
35+
36+
if __name__ == "__main__":
37+
handler({}, {})
38+

0 commit comments

Comments
 (0)