```
note: The majority of content should be under level-3 headers under the "Overview" section
--> Deployment.md:22:1-22:17
20 | * [Third-party tools](#third-party-tools)
21 |
22 + ## Prerequisites
| ╰─suggestion: Change the title to "Overview"
23 |
24 | 1. Your AWS Account
```
and many others.
Action: I lowered all titles one level down.
Add user-facing API for Streaming Lambda functions that receives JSON
events
### Motivation:
Streaming Lambda functions developed by developers had no choice but to
implement a handler that receives incoming data as a `ByteBuffer`. While
this is useful for low-level development, I assume most developers will
want to receive a JSON event to trigger their streaming Lambda function.
Going efficiently from a `ByteBuffer` to a Swift struct requires some
code implemented in the `JSON+ByteBuffer.swift` file of the librray. We
propose to further help developers by providing them with a new
`handler()` function that directly receives their `Decodable` type.
### Modifications:
This PR adds a public facing API (+ unit test + updated README) allowing
developers to write a handler method accepting any `Decodable` struct as
input.
```swift
import AWSLambdaRuntime
import NIOCore
// Define your input event structure
struct StreamingRequest: Decodable {
let count: Int
let message: String
let delayMs: Int?
}
// Use the new streaming handler with JSON decoding
let runtime = LambdaRuntime { (event: StreamingRequest, responseWriter, context: LambdaContext) in
context.logger.info("Received request to send \(event.count) messages")
// Stream the messages
for i in 1...event.count {
let response = "Message \(i)/\(event.count): \(event.message)\n"
try await responseWriter.write(ByteBuffer(string: response))
// Optional delay between messages
if let delay = event.delayMs, delay > 0 {
try await Task.sleep(for: .milliseconds(delay))
}
}
// Finish the stream
try await responseWriter.finish()
// Optional: Execute background work after response is sent
context.logger.info("Background work: processing completed")
}
try await runtime.run()
```
This interface provides:
- **Type-safe JSON input**: Automatic decoding of JSON events into Swift
structs
- **Streaming responses**: Full control over when and how to stream data
back to clients
- **Background work support**: Ability to execute code after the
response stream is finished
- **Familiar API**: Uses the same closure-based pattern as regular
Lambda handlers
Because streaming Lambda functions can be invoked either directly
through the API or through Lambda Function URL, this PR adds the
decoding logic to support both types, shielding developers from working
with Function URL requests and base64 encoding.
We understand these choice will have an impact on the raw performance
for event handling. Those advanced users that want to get the maximum
might use the existing `handler(_ event: ByteBuffer, writer:
LambaStreamingWriter)` function to implement their own custom decoding
logic.
This PR provides a balance between ease of use for 80% of the users vs
ultimate performance, without closing the door for the 20% who need it.
### Result:
Lambda function developers can now use arbitrary `Decodable` Swift
struct or Lambda events to trigger their streaming functions. 🎉
---------
Co-authored-by: Tim Condon <0xTim@users.noreply.github.com>
Add a log statement in the Lambda loop, before calling the user's
handler to show the raw payload before any attempt to decode it.
This was available in Runtime v1 and is now ported to v2.
This fixes
https://github.com/swift-server/swift-aws-lambda-runtime/issues/404
### Motivation:
This is useful when handling custom event and there is a Decoding error.
It allows to see the exact payload received by the handler before any
attempt to decode it.
### Modifications:
Add a log.trace statement with metatadata. Metadata are computed only
when the log level is trace or below.
### Result:
```
2025-07-21T08:58:33+0200 trace LambdaRuntime : Event's first bytes={"name": "me", "age": 50} aws-request-id=769127502334125 [AWSLambdaRuntime] sending invocation event to lambda handler
```
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Add a hard coded version number to the user agent string, for an
eventual identification by the Lambda service
### Motivation:
It's [an
issue](https://github.com/swift-server/swift-aws-lambda-runtime/issues/108)
that was open more than 5 years ago and was never addressed. At the
time, the consensus was to pickup a version number for the Package.swift
file and the maintainer at the time decided to wait for Swift to
implement this.
Five years later, and several major version of Swift later, this is
still not available. I decided to move on and implement a less optimal
solution. This can be replaced in the future if package version ever
becomes part of Package.swift.
### Modifications:
Add a version enum to isolate the versioning in one place. I decided to
keep it simple and not over engineering it with major, minor, patch and
pre-release. At the time, it's a simple string. This is all what we need
for usage in the user agent string.
### Result:
User agent now identifies as `Swift-Lambda/2,0` instead of
`Swift-Lambda/unknown`
This is a proposal to fix issue #507
**changes**
- `LambdaRuntime.init()` uses a `Mutex<Bool>` to make sure only one
instance is created
- `LambdaRuntime.init()` can now throw an error in case an instance
already exists (I did not use `fatalError()` to make it easier to test)
- All `convenience init()` methods catch possible errors instead of
re-throwing it to a void breaking the user-facing API
- Renamed existing `LambdaRuntimeError` to `LambdaRuntimeClientError`
- Introduced a new type `LambdaRuntimeError` to represent the double
initialization error
---------
Co-authored-by: Fabian Fett <fabianfett@apple.com>
Co-authored-by: Adam Fowler <adamfowler71@gmail.com>
Allow user to give their logger to the LambdaRuntime.
### Motivation:
Overloaded versions of `LambdaRuntime.init` don't allow to pass a logger
### Modifications:
Add a `logger` parameter to overloaded versions of `LambdaRuntime.init`
### Result:
It is now possible to write
```
let runtime = LambdaRuntime(logger: Logger(label: "MyLogger"), body: handler)
```
- Add ServiceLifecycle version of `LambdaRuntime.run` that wraps
internal `_run` call in `cancelOnGracefulShutdown`
- Add cancellation handlers for shutting down existing connections in
Local lambda
- Added test for lambda graceful shutdown
### Motivation:
Ensure local lambda supports graceful shutdown
Add SendableMetatype conformance to StreamingLambdaHandler
### Motivation:
Swift 6.2 introduced new protocol SendableMetatype for Types that are
Sendable
### Modifications:
Added `_Lambda_SendableMetatype` typealias for SendableMetatype in Swift
6.2
and
```swift
public protocol StreamingLambdaHandler: _Lambda_SendableMetatype {
```
### Result:
No more compile warnings
The user-agent string was repeated at 5+ different places in the source
code.
I defined it as a constant in the `ControlPlaneRequest` struct where
other similar constant have been defined and make sure the rest of the
code only uses that constant.
This should address
https://github.com/swift-server/swift-aws-lambda-runtime/issues/492
Allow `LambdaChannelHandler.nextInvocation` to be cancelled.
### Motivation:
If we want to use ServiceLifecycle with the lambda runtime the lambda
runtime needs to be cancellable either via a ServiceLifecycle graceful
shutdown or via Task cancellation. To avoid bringing in the
ServiceLifecycle dependency this PR adds cancellation via Task
cancellation handler.
### Modifications:
Add `withTaskCancellationHandler` to nextInvocation which calls close on
cancel.
In `LambdaChannelHandler.channelInactive` resume continuation if state
is `waitingForNextInvocation`
Added `LambdaRuntimeClientTests.testCancellation`
### Result:
You can now cancel the runtime while it is waiting for the next
invocation.
---------
Co-authored-by: Fabian Fett <fabianfett@apple.com>
Co-authored-by: Sébastien Stormacq <sebastien.stormacq@gmail.com>
Add a note in the deployment guide to inform Linux user they must have
correct permissions to use docker on their system.
### Motivation:
Build instructions fail on a fresh Ubuntu installation. See this error
report.
https://github.com/swift-server/swift-aws-lambda-runtime/issues/449
### Modifications:
Add a note in the deployment guide that Linux user must add their user
in the `docker` group.
### Result:
Hopefully, Linux users will not experience error at first use of `swift
package archive`
As discussed with @0xTim
This PR
- adds a minimal example of deployment using SAM in the README
- adds a `Deployment.md` Swift Docc file to cover deployment with the
AWS console, CLI, SAM, and CDK. It mentions and contains a call to
contributions to further examples for third-party tools such as the
Serverless Framework, Terraform, or Pulumi.
All the `Package.swift` files from the examples use `path: "."` instead
of `path: "Sources"` which triggers error messages when users add a
`Tests` directory.
We want that the runtime only depends on `FoundationEssentials` where
available (ie. on linux) to ensure small binary size.
### Motivation:
Smaller binary size is good for lambda deployment and cold-start times.
The runtime should only depend on `FoundationEssentials`.
### Modifications:
- replace `import Foundation` with `import FoundationEssentials` if
`FoundationEssentials` is available.
- I also applied the same treatment to tests to ensure that catch error
where tests run on linux and we use API that is only available in
`Foundation` which easily happens when you develop on macOS (where
always full `Foundation` is available).
### Result:
This should allow builds without linking full `Foundation`.