Skip to content

Commit 70bd332

Browse files
brienseaPartiallyUntypedStefan9283trivenaydtorok
authored
Sync with Public (#2)
* Patch libcurl configure.ac to work with later versions of autoconf (#168) Added a patch for libcurl/configure.ac to fix build issues with recent versions of autoconf This commit adds a patch for curl/configure.ac that replaces the inlined flags/conditionals with scoped ones. What's happening? 1. We have build failures in later versions of autoconf. 1. Why ? ./configure script for libcurl breaks during execution. 2. Why ? Control flow structures are not correctly closed which results in a parse error. 3. Why ? The structures in the m4 template in ./configure.ac for the 7.83.1 release of libcurl rely on inlined scripts. 4. Why [now]? The 2.72 update on autoconf changed the behaviour of the script generator. What do we do to ameliorate this? 1. Corrected the config script 2. Created a patch 3. Apply the patch to the shipped curl dependency * Update version to 2.2.1 (#170) * Add python3.13. (#175) * Add python3.13. * Fix integ tests --------- Co-authored-by: Stefan Toma <[email protected]> * Add support for snapstart runtime hooks (#176) * Bump version to 3.0.0 (#178) * Drop support for deprecated python versions (#179) * Change warning message to JSON (#182) * Bump to version 3.0.1. (#183) * Update simplejson to 3.20.1 (#184) * Update to simplejson 3.20.1 * Bump to version 3.0.2. (#185) * Sync with aws-lambda-python-runtime-interface-client repository --------- Co-authored-by: Quinn Sinclair <[email protected]> Co-authored-by: Stefan Toma <[email protected]> Co-authored-by: trivenay <[email protected]> Co-authored-by: Daniel Torok <[email protected]>
1 parent a287869 commit 70bd332

28 files changed

+779
-46
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,8 @@ cython_debug/
148148

149149
# Test files generated
150150
tmp*.py
151+
152+
# dependencies
153+
deps/artifacts/
154+
deps/aws-lambda-cpp-*/
155+
deps/curl-*/

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ repos:
33
rev: 19.3b0
44
hooks:
55
- id: black
6-
language_version: python3.6
6+
language_version: python3.9
77
exclude_types: ['markdown', 'ini', 'toml', 'rst']

README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ We have open-sourced a set of software packages, Runtime Interface Clients (RIC)
55
base images to be Lambda compatible.
66
The Lambda Runtime Interface Client is a lightweight interface that allows your runtime to receive requests from and send requests to the Lambda service.
77

8-
The Lambda Python Runtime Interface Client is vended through [pip](https://pypi.org/project/awslambdaric).
8+
The Lambda Python Runtime Interface Client is vended through [pip](https://pypi.org/project/awslambdaric).
99
You can include this package in your preferred base image to make that base image Lambda compatible.
1010

1111
## Requirements
1212
The Python Runtime Interface Client package currently supports Python versions:
13-
- 3.7.x up to and including 3.12.x
13+
- 3.9.x up to and including 3.13.x
1414

1515
## Usage
1616

@@ -103,18 +103,18 @@ def handler(event, context):
103103

104104
### Local Testing
105105

106-
To make it easy to locally test Lambda functions packaged as container images we open-sourced a lightweight web-server, Lambda Runtime Interface Emulator (RIE), which allows your function packaged as a container image to accept HTTP requests. You can install the [AWS Lambda Runtime Interface Emulator](https://github.com/aws/aws-lambda-runtime-interface-emulator) on your local machine to test your function. Then when you run the image function, you set the entrypoint to be the emulator.
106+
To make it easy to locally test Lambda functions packaged as container images we open-sourced a lightweight web-server, Lambda Runtime Interface Emulator (RIE), which allows your function packaged as a container image to accept HTTP requests. You can install the [AWS Lambda Runtime Interface Emulator](https://github.com/aws/aws-lambda-runtime-interface-emulator) on your local machine to test your function. Then when you run the image function, you set the entrypoint to be the emulator.
107107

108108
*To install the emulator and test your Lambda function*
109109

110-
1) From your project directory, run the following command to download the RIE from GitHub and install it on your local machine.
110+
1) From your project directory, run the following command to download the RIE from GitHub and install it on your local machine.
111111

112112
```shell script
113113
mkdir -p ~/.aws-lambda-rie && \
114114
curl -Lo ~/.aws-lambda-rie/aws-lambda-rie https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie && \
115115
chmod +x ~/.aws-lambda-rie/aws-lambda-rie
116116
```
117-
2) Run your Lambda image function using the docker run command.
117+
2) Run your Lambda image function using the docker run command.
118118

119119
```shell script
120120
docker run -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \
@@ -123,9 +123,9 @@ docker run -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \
123123
/usr/local/bin/python -m awslambdaric app.handler
124124
```
125125

126-
This runs the image as a container and starts up an endpoint locally at `http://localhost:9000/2015-03-31/functions/function/invocations`.
126+
This runs the image as a container and starts up an endpoint locally at `http://localhost:9000/2015-03-31/functions/function/invocations`.
127127

128-
3) Post an event to the following endpoint using a curl command:
128+
3) Post an event to the following endpoint using a curl command:
129129

130130
```shell script
131131
curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
@@ -174,4 +174,4 @@ If you discover a potential security issue in this project we ask that you notif
174174

175175
## License
176176

177-
This project is licensed under the Apache-2.0 License.
177+
This project is licensed under the Apache-2.0 License.

RELEASE.CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
### February 27, 2024
2+
`3.0.2`
3+
- Update `simplejson` to `3.20.1`([#184](https://github.com/aws/aws-lambda-python-runtime-interface-client/pull/184))
4+
5+
### January 27, 2024
6+
`3.0.1`
7+
- Don't enforce text format on uncaught exception warning message ([#182](https://github.com/aws/aws-lambda-python-runtime-interface-client/pull/182))
8+
9+
### November 19, 2024
10+
`3.0.0`
11+
- Drop support for deprecated python versions ([#179](https://github.com/aws/aws-lambda-python-runtime-interface-client/pull/179))
12+
- Add support for snapstart runtime hooks ([#176](https://github.com/aws/aws-lambda-python-runtime-interface-client/pull/176))
13+
14+
### August 23, 2024
15+
`2.2.1`:
16+
- Patch libcurl configure.ac to work with later versions of autoconf ([#166](https://github.com/aws/aws-lambda-python-runtime-interface-client/pull/168))
17+
118
### August 8, 2024
219

320
`2.2.0`:

awslambdaric/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
33
"""
44

5-
__version__ = "2.2.0"
5+
__version__ = "3.0.2"

awslambdaric/bootstrap.py

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
_AWS_LAMBDA_LOG_LEVEL = _get_log_level_from_env_var(
3232
os.environ.get("AWS_LAMBDA_LOG_LEVEL")
3333
)
34+
AWS_LAMBDA_INITIALIZATION_TYPE = "AWS_LAMBDA_INITIALIZATION_TYPE"
35+
INIT_TYPE_SNAP_START = "snap-start"
3436

3537

3638
def _get_handler(handler):
@@ -100,7 +102,6 @@ def replace_line_indentation(line, indent_char, new_indent_char):
100102

101103
if _AWS_LAMBDA_LOG_FORMAT == LogFormat.JSON:
102104
_ERROR_FRAME_TYPE = _JSON_FRAME_TYPES[logging.ERROR]
103-
_WARNING_FRAME_TYPE = _JSON_FRAME_TYPES[logging.WARNING]
104105

105106
def log_error(error_result, log_sink):
106107
error_result = {
@@ -116,7 +117,6 @@ def log_error(error_result, log_sink):
116117

117118
else:
118119
_ERROR_FRAME_TYPE = _TEXT_FRAME_TYPES[logging.ERROR]
119-
_WARNING_FRAME_TYPE = _TEXT_FRAME_TYPES[logging.WARNING]
120120

121121
def log_error(error_result, log_sink):
122122
error_description = "[ERROR]"
@@ -201,7 +201,7 @@ def handle_event_request(
201201
if error_result is not None:
202202
from .lambda_literals import lambda_unhandled_exception_warning_message
203203

204-
log_sink.log(lambda_unhandled_exception_warning_message, _WARNING_FRAME_TYPE)
204+
logging.warning(lambda_unhandled_exception_warning_message)
205205
log_error(error_result, log_sink)
206206
lambda_runtime_client.post_invocation_error(
207207
invoke_id, to_json(error_result), to_json(xray_fault)
@@ -286,6 +286,29 @@ def extract_traceback(tb):
286286
]
287287

288288

289+
def on_init_complete(lambda_runtime_client, log_sink):
290+
from . import lambda_runtime_hooks_runner
291+
292+
try:
293+
lambda_runtime_hooks_runner.run_before_snapshot()
294+
lambda_runtime_client.restore_next()
295+
except:
296+
error_result = build_fault_result(sys.exc_info(), None)
297+
log_error(error_result, log_sink)
298+
lambda_runtime_client.post_init_error(
299+
error_result, FaultException.BEFORE_SNAPSHOT_ERROR
300+
)
301+
sys.exit(64)
302+
303+
try:
304+
lambda_runtime_hooks_runner.run_after_restore()
305+
except:
306+
error_result = build_fault_result(sys.exc_info(), None)
307+
log_error(error_result, log_sink)
308+
lambda_runtime_client.report_restore_error(error_result)
309+
sys.exit(65)
310+
311+
289312
class LambdaLoggerHandler(logging.Handler):
290313
def __init__(self, log_sink):
291314
logging.Handler.__init__(self)
@@ -454,9 +477,10 @@ def run(app_root, handler, lambda_runtime_api_addr):
454477
sys.stdout = Unbuffered(sys.stdout)
455478
sys.stderr = Unbuffered(sys.stderr)
456479

457-
use_thread_for_polling_next = (
458-
os.environ.get("AWS_EXECUTION_ENV") == "AWS_Lambda_python3.12"
459-
)
480+
use_thread_for_polling_next = os.environ.get("AWS_EXECUTION_ENV") in {
481+
"AWS_Lambda_python3.12",
482+
"AWS_Lambda_python3.13",
483+
}
460484

461485
with create_log_sink() as log_sink:
462486
lambda_runtime_client = LambdaRuntimeClient(
@@ -484,6 +508,9 @@ def run(app_root, handler, lambda_runtime_api_addr):
484508

485509
sys.exit(1)
486510

511+
if os.environ.get(AWS_LAMBDA_INITIALIZATION_TYPE) == INIT_TYPE_SNAP_START:
512+
on_init_complete(lambda_runtime_client, log_sink)
513+
487514
while True:
488515
event_request = lambda_runtime_client.wait_next_invocation()
489516

awslambdaric/lambda_runtime_client.py

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,25 +62,57 @@ def __init__(self, lambda_runtime_address, use_thread_for_polling_next=False):
6262
# Not defining symbol as global to avoid relying on TPE being imported unconditionally.
6363
self.ThreadPoolExecutor = ThreadPoolExecutor
6464

65-
def post_init_error(self, error_response_data):
65+
def call_rapid(
66+
self, http_method, endpoint, expected_http_code, payload=None, headers=None
67+
):
6668
# These imports are heavy-weight. They implicitly trigger `import ssl, hashlib`.
6769
# Importing them lazily to speed up critical path of a common case.
68-
import http
6970
import http.client
7071

7172
runtime_connection = http.client.HTTPConnection(self.lambda_runtime_address)
7273
runtime_connection.connect()
73-
endpoint = "/2018-06-01/runtime/init/error"
74-
headers = {ERROR_TYPE_HEADER: error_response_data["errorType"]}
75-
runtime_connection.request(
76-
"POST", endpoint, to_json(error_response_data), headers=headers
77-
)
74+
if http_method == "GET":
75+
runtime_connection.request(http_method, endpoint)
76+
else:
77+
runtime_connection.request(
78+
http_method, endpoint, to_json(payload), headers=headers
79+
)
80+
7881
response = runtime_connection.getresponse()
7982
response_body = response.read()
80-
81-
if response.code != http.HTTPStatus.ACCEPTED:
83+
if response.code != expected_http_code:
8284
raise LambdaRuntimeClientError(endpoint, response.code, response_body)
8385

86+
def post_init_error(self, error_response_data, error_type_override=None):
87+
import http
88+
89+
endpoint = "/2018-06-01/runtime/init/error"
90+
headers = {
91+
ERROR_TYPE_HEADER: (
92+
error_type_override
93+
if error_type_override
94+
else error_response_data["errorType"]
95+
)
96+
}
97+
self.call_rapid(
98+
"POST", endpoint, http.HTTPStatus.ACCEPTED, error_response_data, headers
99+
)
100+
101+
def restore_next(self):
102+
import http
103+
104+
endpoint = "/2018-06-01/runtime/restore/next"
105+
self.call_rapid("GET", endpoint, http.HTTPStatus.OK)
106+
107+
def report_restore_error(self, restore_error_data):
108+
import http
109+
110+
endpoint = "/2018-06-01/runtime/restore/error"
111+
headers = {ERROR_TYPE_HEADER: FaultException.AFTER_RESTORE_ERROR}
112+
self.call_rapid(
113+
"POST", endpoint, http.HTTPStatus.ACCEPTED, restore_error_data, headers
114+
)
115+
84116
def wait_next_invocation(self):
85117
# Calling runtime_client.next() from a separate thread unblocks the main thread,
86118
# which can then process signals.

awslambdaric/lambda_runtime_exception.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ class FaultException(Exception):
1111
IMPORT_MODULE_ERROR = "Runtime.ImportModuleError"
1212
BUILT_IN_MODULE_CONFLICT = "Runtime.BuiltInModuleConflict"
1313
MALFORMED_HANDLER_NAME = "Runtime.MalformedHandlerName"
14+
BEFORE_SNAPSHOT_ERROR = "Runtime.BeforeSnapshotError"
15+
AFTER_RESTORE_ERROR = "Runtime.AfterRestoreError"
1416
LAMBDA_CONTEXT_UNMARSHAL_ERROR = "Runtime.LambdaContextUnmarshalError"
1517
LAMBDA_RUNTIME_CLIENT_ERROR = "Runtime.LambdaRuntimeClientError"
1618

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
from snapshot_restore_py import get_before_snapshot, get_after_restore
5+
6+
7+
def run_before_snapshot():
8+
before_snapshot_callables = get_before_snapshot()
9+
while before_snapshot_callables:
10+
# Using pop as before checkpoint callables are executed in the reverse order of their registration
11+
func, args, kwargs = before_snapshot_callables.pop()
12+
func(*args, **kwargs)
13+
14+
15+
def run_after_restore():
16+
after_restore_callables = get_after_restore()
17+
for func, args, kwargs in after_restore_callables:
18+
func(*args, **kwargs)

awslambdaric/lambda_runtime_marshaller.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
# We also set 'ensure_ascii=False' so that the encoded json contains unicode characters instead of unicode escape sequences
1616
class Encoder(json.JSONEncoder):
1717
def __init__(self):
18-
if os.environ.get("AWS_EXECUTION_ENV") == "AWS_Lambda_python3.12":
18+
if os.environ.get("AWS_EXECUTION_ENV") in {
19+
"AWS_Lambda_python3.12",
20+
"AWS_Lambda_python3.13",
21+
}:
1922
super().__init__(use_decimal=False, ensure_ascii=False, allow_nan=True)
2023
else:
2124
super().__init__(use_decimal=False, allow_nan=True)

0 commit comments

Comments
 (0)