-
Notifications
You must be signed in to change notification settings - Fork 118
Add support for Lambda Managed Instances without changing the public API #623
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
sebsto
wants to merge
14
commits into
main
Choose a base branch
from
sebsto/lambda-managed-instances-v2
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
2db6f9a
remove unused script
sebsto e01ef93
refcator files on Lambda runtime
sebsto 2766f3f
add support for LLambda Managed Instances
sebsto a9bc954
add examples
sebsto 4610626
Merge branch 'main' into sebsto/lambda-managed-instances-v2
sebsto 79408e7
swift format
sebsto 0f93212
cleanup
sebsto ec514de
fix yaml lint
sebsto e6ceca8
fix missing license header
sebsto e3d37e8
add Managed Instances to the integration tests
sebsto c435933
add some tests for LambdaManagedRuntime
sebsto 8ea2da5
Update Examples/ManagedInstances/Sources/Streaming/main.swift
sebsto 32d62a1
fix typos
sebsto 08032de
add lambda managed instances section in the readme
sebsto File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
This file contains hidden or 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,3 @@ | ||
| response.json | ||
| samconfig.toml | ||
| Makefile |
This file contains hidden or 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,46 @@ | ||
| // swift-tools-version:6.2 | ||
|
|
||
| import PackageDescription | ||
|
|
||
| let package = Package( | ||
| name: "swift-aws-lambda-runtime-example", | ||
| platforms: [.macOS(.v15)], | ||
| products: [ | ||
| .executable(name: "HelloJSON", targets: ["HelloJSON"]), | ||
| .executable(name: "Streaming", targets: ["Streaming"]), | ||
| .executable(name: "BackgroundTasks", targets: ["BackgroundTasks"]), | ||
| ], | ||
| dependencies: [ | ||
| // For local development (default) | ||
| .package(name: "swift-aws-lambda-runtime", path: "../.."), | ||
|
|
||
| // For standalone usage, comment the line above and uncomment below: | ||
| // .package(url: "https://github.com/awslabs/swift-aws-lambda-runtime.git", from: "2.0.0"), | ||
|
|
||
| .package(url: "https://github.com/awslabs/swift-aws-lambda-events.git", from: "1.0.0"), | ||
| ], | ||
| targets: [ | ||
| .executableTarget( | ||
| name: "HelloJSON", | ||
| dependencies: [ | ||
| .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime") | ||
| ], | ||
| path: "Sources/HelloJSON" | ||
| ), | ||
| .executableTarget( | ||
| name: "Streaming", | ||
| dependencies: [ | ||
| .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), | ||
| .product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"), | ||
| ], | ||
| path: "Sources/Streaming" | ||
| ), | ||
| .executableTarget( | ||
| name: "BackgroundTasks", | ||
| dependencies: [ | ||
| .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime") | ||
| ], | ||
| path: "Sources/BackgroundTasks" | ||
| ), | ||
| ] | ||
| ) |
This file contains hidden or 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,126 @@ | ||
| # Lambda Managed Instances Example | ||
|
|
||
| This example demonstrates deploying Swift Lambda functions to Lambda Managed Instances using AWS SAM. Lambda Managed Instances provide serverless simplicity with EC2 flexibility and cost optimization by running your functions on customer-owned EC2 instances. | ||
|
|
||
| ## Functions Included | ||
|
|
||
| 1. **HelloJSON** - JSON input/output with structured data types | ||
| 2. **Streaming** - Demonstrates response streaming capabilities | ||
| 3. **BackgroundTasks** - Handles long-running background processing | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - AWS CLI configured with appropriate permissions | ||
| - SAM CLI installed | ||
| - Swift 6.0+ installed | ||
| - An existing [Lambda Managed Instances capacity provider](https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances-capacity-providers.html) | ||
|
|
||
| ## Capacity Provider Configuration | ||
|
|
||
| [Create your own capacity provider](https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances-capacity-providers.html#lambda-managed-instances-creating-capacity-provider) before deploying this example. | ||
|
|
||
| This example uses a pre-configured capacity provider with the ARN: | ||
| ``` | ||
| arn:aws:lambda:us-west-2:486652066693:capacity-provider:TestEC2 | ||
| ``` | ||
|
|
||
| ## Deployment | ||
|
|
||
| ```bash | ||
| # Build the Swift packages | ||
| swift package archive --allow-network-access docker | ||
|
|
||
| # Change the values below to match your setup | ||
| REGION=us-west-2 | ||
| CAPACITY_PROVIDER=arn:aws:lambda:us-west-2:<YOUR ACCOUNT ID>:capacity-provider:<YOUR CAPACITY PROVIDER NAME> | ||
|
|
||
| # Deploy using SAM | ||
| sam deploy \ | ||
| --resolve-s3 \ | ||
| --template-file template.yaml \ | ||
| --stack-name swift-lambda-managed-instances \ | ||
| --capabilities CAPABILITY_IAM \ | ||
| --region ${REGION} \ | ||
| --parameter-overrides \ | ||
| CapacityProviderArn=${CAPACITY_PROVIDER} | ||
| ``` | ||
|
|
||
| ## Function Details | ||
|
|
||
| ### HelloJSON Function | ||
| - **Timeout**: 15 seconds (default) | ||
| - **Concurrency**: 8 per execution environment (default) | ||
| - **Input**: JSON `{"name": "string", "age": number}` | ||
| - **Output**: JSON `{"greetings": "string"}` | ||
|
|
||
| ### Streaming Function | ||
| - **Timeout**: 60 seconds | ||
| - **Concurrency**: 8 per execution environment (default) | ||
| - **Features**: Response streaming enabled | ||
| - **Output**: Streams numbers with pauses | ||
|
|
||
| ### BackgroundTasks Function | ||
| - **Timeout**: 300 seconds (5 minutes) | ||
| - **Concurrency**: 8 per execution environment (default) | ||
| - **Input**: JSON `{"message": "string"}` | ||
| - **Features**: Long-running background processing after response | ||
|
|
||
| ## Testing with AWS CLI | ||
|
|
||
| After deployment, invoke each function with the AWS CLI: | ||
|
|
||
| ### Test HelloJSON Function | ||
| ```bash | ||
| REGION=us-west-2 | ||
| aws lambda invoke \ | ||
| --region ${REGION} \ | ||
| --function-name swift-lambda-managed-instances-HelloJSON \ | ||
| --payload $(echo '{ "name" : "Swift Developer", "age" : 50 }' | base64) \ | ||
| out.txt && cat out.txt && rm out.txt | ||
|
|
||
| # Expected output: {"greetings": "Hello Swift Developer. You look older than your age."} | ||
| ``` | ||
|
|
||
| ### Test Streaming Function | ||
| ```bash | ||
| # Get the Streaming URL | ||
| REGION=us-west-2 | ||
| STREAMING_URL=$(aws cloudformation describe-stacks \ | ||
| --stack-name swift-lambda-managed-instances \ | ||
| --region ${REGION} \ | ||
| --query 'Stacks[0].Outputs[?OutputKey==`StreamingFunctionUrl`].OutputValue' \ | ||
| --output text) | ||
|
|
||
| # Set the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN environment variables | ||
| eval $(aws configure export-credentials --format env) | ||
|
|
||
| # Test with curl (streaming response) | ||
| curl "$STREAMING_URL" \ | ||
| --user "${AWS_ACCESS_KEY_ID}":"${AWS_SECRET_ACCESS_KEY}" \ | ||
| --aws-sigv4 "aws:amz:${REGION}:lambda" \ | ||
| -H "x-amz-security-token: ${AWS_SESSION_TOKEN}" \ | ||
| --no-buffer | ||
|
|
||
| # Expected output: Numbers streaming with pauses | ||
| ``` | ||
|
|
||
| ### Test BackgroundTasks Function | ||
| ```bash | ||
| # Test with AWS CLI | ||
| REGION=us-west-2 | ||
| aws lambda invoke \ | ||
| --region ${REGION} \ | ||
| --function-name swift-lambda-managed-instances-BackgroundTasks \ | ||
| --payload $(echo '{ "message" : "Additional processing in the background" }' | base64) \ | ||
| out.txt && cat out.txt && rm out.txt | ||
|
|
||
| # Expected output: {"echoedMessage": "Additional processing in the background"} | ||
| # Note: Background processing continues after response is sent | ||
| ``` | ||
|
|
||
| ## Cleanup | ||
|
|
||
| To remove all resources: | ||
| ```bash | ||
| sam delete --stack-name swift-lambda-managed-instances --region ${REGION} | ||
| ``` | ||
60 changes: 60 additions & 0 deletions
60
Examples/ManagedInstances/Sources/BackgroundTasks/main.swift
This file contains hidden or 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,60 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This source file is part of the SwiftAWSLambdaRuntime open source project | ||
| // | ||
| // Copyright SwiftAWSLambdaRuntime project authors | ||
| // Copyright (c) Amazon.com, Inc. or its affiliates. | ||
| // Licensed under Apache License v2.0 | ||
| // | ||
| // See LICENSE.txt for license information | ||
| // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors | ||
| // | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| import AWSLambdaRuntime | ||
|
|
||
| #if canImport(FoundationEssentials) | ||
| import FoundationEssentials | ||
| #else | ||
| import Foundation | ||
| #endif | ||
|
|
||
| // for a simple struct as this one, the compiler automatically infers Sendable | ||
| // With Lambda Managed Instances, your handler struct MUST be Sendable | ||
| struct BackgroundProcessingHandler: LambdaWithBackgroundProcessingHandler, Sendable { | ||
| struct Input: Decodable { | ||
| let message: String | ||
| } | ||
|
|
||
| struct Greeting: Encodable { | ||
| let echoedMessage: String | ||
| } | ||
|
|
||
| typealias Event = Input | ||
| typealias Output = Greeting | ||
|
|
||
| func handle( | ||
| _ event: Event, | ||
| outputWriter: some LambdaResponseWriter<Output>, | ||
| context: LambdaContext | ||
| ) async throws { | ||
| // Return result to the Lambda control plane | ||
| context.logger.debug("BackgroundProcessingHandler - message received") | ||
| try await outputWriter.write(Greeting(echoedMessage: event.message)) | ||
|
|
||
| // Perform some background work, e.g: | ||
| context.logger.debug("BackgroundProcessingHandler - response sent. Performing background tasks.") | ||
| try await Task.sleep(for: .seconds(10)) | ||
|
|
||
| // Exit the function. All asynchronous work has been executed before exiting the scope of this function. | ||
| // Follows structured concurrency principles. | ||
| context.logger.debug("BackgroundProcessingHandler - Background tasks completed. Returning") | ||
| return | ||
| } | ||
| } | ||
|
|
||
| let adapter = LambdaCodableAdapterSendable(handler: BackgroundProcessingHandler()) | ||
| let runtime = LambdaManagedRuntime(handler: adapter) | ||
| try await runtime.run() |
This file contains hidden or 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,41 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This source file is part of the SwiftAWSLambdaRuntime open source project | ||
| // | ||
| // Copyright SwiftAWSLambdaRuntime project authors | ||
| // Copyright (c) Amazon.com, Inc. or its affiliates. | ||
| // Licensed under Apache License v2.0 | ||
| // | ||
| // See LICENSE.txt for license information | ||
| // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors | ||
| // | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| import AWSLambdaRuntime | ||
|
|
||
| // in this example we are receiving and responding with JSON structures | ||
|
|
||
| // the data structure to represent the input parameter | ||
| struct HelloRequest: Decodable { | ||
| let name: String | ||
| let age: Int | ||
| } | ||
|
|
||
| // the data structure to represent the output response | ||
| struct HelloResponse: Encodable { | ||
| let greetings: String | ||
| } | ||
|
|
||
| // the Lambda runtime | ||
| let runtime = LambdaManagedRuntime { | ||
| (event: HelloRequest, context: LambdaContext) in | ||
|
|
||
| HelloResponse( | ||
| greetings: "Hello \(event.name). You look \(event.age > 30 ? "younger" : "older") than your age." | ||
| ) | ||
| } | ||
|
|
||
| // start the loop | ||
| try await runtime.run() |
This file contains hidden or 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,69 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This source file is part of the SwiftAWSLambdaRuntime open source project | ||
| // | ||
| // Copyright SwiftAWSLambdaRuntime project authors | ||
| // Copyright (c) Amazon.com, Inc. or its affiliates. | ||
| // Licensed under Apache License v2.0 | ||
| // | ||
| // See LICENSE.txt for license information | ||
| // See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors | ||
| // | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| import AWSLambdaEvents | ||
| import AWSLambdaRuntime | ||
| import NIOCore | ||
|
|
||
| #if canImport(FoundationEssentials) | ||
| import FoundationEssentials | ||
| #else | ||
| import Foundation | ||
| #endif | ||
|
|
||
| // for a simple struct as this one, the compiler automatically infers Sendable | ||
| // With Lambda Managed Instances, your handler struct MUST be Sendable | ||
| struct SendNumbersWithPause: StreamingLambdaHandler, Sendable { | ||
| func handle( | ||
| _ event: ByteBuffer, | ||
| responseWriter: some LambdaResponseStreamWriter, | ||
| context: LambdaContext | ||
| ) async throws { | ||
|
|
||
| // The payload here is a Lambda Function URL request | ||
| // Check the body of the Function URL request to extract the business event | ||
| let payload = try JSONDecoder().decode(FunctionURLRequest.self, from: Data(event.readableBytesView)) | ||
| let _ = payload.body | ||
|
|
||
| // Send HTTP status code and headers before streaming the response body | ||
| try await responseWriter.writeStatusAndHeaders( | ||
| StreamingLambdaStatusAndHeadersResponse( | ||
| statusCode: 418, // I'm a tea pot | ||
| headers: [ | ||
| "Content-Type": "text/plain", | ||
| "x-my-custom-header": "streaming-example", | ||
| ] | ||
| ) | ||
| ) | ||
|
|
||
| // Stream numbers with pauses to demonstrate streaming functionality | ||
| for i in 1...3 { | ||
| // Send partial data | ||
| try await responseWriter.write(ByteBuffer(string: "Number: \(i)\n")) | ||
|
|
||
| // Perform some long asynchronous work to simulate processing | ||
| try await Task.sleep(for: .milliseconds(1000)) | ||
| } | ||
|
|
||
| // Send final message | ||
| try await responseWriter.write(ByteBuffer(string: "Streaming complete!\n")) | ||
|
|
||
| // All data has been sent. Close off the response stream. | ||
| try await responseWriter.finish() | ||
| } | ||
| } | ||
|
|
||
| let runtime = LambdaManagedRuntime(handler: SendNumbersWithPause()) | ||
| try await runtime.run() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.