Commit Graph

420 Commits

Author SHA1 Message Date
Sébastien Stormacq a8a54d9d98 Add docc for Lambda Managed Instances (#637)
Add a docc page to cover Lambda Managed instanced added at version 2.6.0

---------

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2.6.1
2026-02-12 15:32:17 +01:00
Sébastien Stormacq 190eb81876 Add support for Lambda Managed Instances without changing the public API [Convenience + Example] (#623)
This PR builds on
https://github.com/awslabs/swift-aws-lambda-runtime/pull/629 to add
convenience structs (Handlers and Adapters) that are `Sendable`

**Changes**

- **Added Sendable adapter types**: Implemented `ClosureHandlerSendable`
- a thread-safe version of existing closure handler that enforces
`Sendable` conformance for concurrent execution environments - and added
conditional conformance to `Sendable` for other Adapters when the
Handler is `Sendable`

- **Enhanced handler protocols for concurrency**: Extended handler
protocols to support `Sendable` constraints and concurrent response
writing through `LambdaResponseStreamWriter & Sendable`, enabling safe
multi-threaded invocation processing

- **Created comprehensive Lambda Managed Instances examples**: Built
three demonstration functions showcasing concurrent execution
capabilities, streaming responses, and background processing patterns
specific to the new managed instances deployment model

**Context**
Lambda Managed Instances support multi-concurrent invocations where
multiple invocations execute simultaneously within the same execution
environment. The runtime now detects the configured concurrency level
and launches the appropriate number of RICs to handle concurrent
requests efficiently.

When `AWS_LAMBDA_MAX_CONCURRENCY` is 1 or unset, the runtime maintains
the existing single-threaded behaviour for optimal performance on
traditional Lambda deployments.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2.6.0
2026-02-12 00:32:31 +01:00
Sébastien Stormacq d456396581 Add support for Lambda Managed Instances without changing the public API [CORE] (#629)
AWS launched [Lambda Managed
Instances](https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances.html),
i.e Lambda functions running on EC2 instances.

This comes with [a major change in the programming
model](https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances.html#lambda-managed-instances-concurrency-model)
as function handlers are now allowed to run concurrently on the same
machine (multiple in flight events being processed in parallel in the
same execution environment). The maximum concurrency per runtime
environment is controlled by the user.

This PR adds support for running multiple Runtime Interface Clients
(RICs) concurrently when deployed on Lambda Managed Instances, enabling
the runtime to handle multiple invocations simultaneously within a
single execution environment.

This PR is a followup to
https://github.com/awslabs/swift-aws-lambda-runtime/pull/617 which used
another approach to support Lambda Managed Instances by changing the
public API and requiring that all handlers must conform to `Sendable`.
The original PR was closed as we agreed that only a fraction of the
Lambda functions will be deployed on EC2 and it was not worth adding a
`Sendable` requirement for all.

**Changes**

- **Introduced thread-safe LambdaManagedRuntime**: Created new
Sendable-conforming runtime class that supports concurrent handler
execution with atomic guards to prevent multiple runtime instances and
thread-safe handler requirements (`Handler: StreamingLambdaHandler &
Sendable`)

- **Implemented ServiceLifecycle integration**: Added managed runtime
support for structured concurrency lifecycle management, allowing proper
startup/shutdown coordination in multi-concurrent environments

This PR contains only changes to the core runtime, convenience
functions, handlers, adapters, and a comprehensive example will be added
in a follow up PR.

**Context**
Lambda Managed Instances support multi-concurrent invocations where
multiple invocations execute simultaneously within the same execution
environment. The runtime now detects the configured concurrency level
and launches the appropriate number of RICs to handle concurrent
requests efficiently.

When `AWS_LAMBDA_MAX_CONCURRENCY` is 1 or unset, the runtime maintains
the existing single-threaded behaviour for optimal performance on
traditional Lambda deployments.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2026-02-12 00:17:04 +01:00
Sebastien Stormacq ba48cf70b0 Add source terminal image in tutorial 2026-02-08 06:30:56 +01:00
Sébastien Stormacq 4815273dc3 Fix race condition in Lambda+LocalServer causing NIOAsyncWriter fatal error (Bug #635) (#636)
On fast machines, the local Lambda server crashes with:
```
Fatal error: Deinited NIOAsyncWriter without calling finish()
```

This occurs in `NIOAsyncChannelHandler.channelActive()` when child
connection channels are created.

## Root Cause

This is a known issue with NIO's async server channel API (see
[swift-nio#2637](https://github.com/apple/swift-nio/issues/2637)).

**The fundamental problem:**

1. The async `bind()` API creates `NIOAsyncChannel` instances for
incoming connections
2. These channels are yielded through an async stream to the server loop
3. When the serving task is cancelled (or completes), the async stream
iteration stops
4. Any channels that were accepted but not yet read from the stream are
dropped
5. These unread channels never have `executeThenClose()` called on them
6. Their `NIOAsyncWriter` is deallocated without `finish()` being called
→ fatal error

**Why graceful shutdown doesn't help:**

Even closing the server channel gracefully doesn't eliminate the race -
there's a timing window where:
- A connection is accepted and queued in the async stream
- The server task is cancelled or completes
- The queued channel is never read and gets dropped

IMHO, this is an inherent limitation of the `async bind()` API when
combined with task cancellation.

## Solution

I stopped using the `async bind()` API entirely. Instead, I use the
traditional callback-based `childChannelInitializer`:

1. Create `NIOAsyncChannel` directly in `childChannelInitializer`
(synchronous context)
2. Immediately spawn a `Task.detached` to handle the connection
3. Each connection is handled independently, not through a cancellable
async stream
4. Detached tasks are not affected by task group cancellation
5. Every channel has `executeThenClose()` called immediately, preventing
the writer from being dropped

This approach avoids the async stream entirely, eliminating the race
condition.

## Changes

- Replaced `async bind()` with traditional `childChannelInitializer`
- Each connection spawns a `Task.detached` that immediately calls
`executeThenClose()`
- Removed the connection iteration loop (no longer needed)
- Server task now simply waits for the channel to close
- Simplified shutdown logic since there's no async stream to drain

## Trade-offs

- Uses `Task.detached` (unstructured concurrency) to bridge NIO's
event-loop world with Swift concurrency
- This is necessary until NIO provides a new bootstrap API that properly
handles cancellation
- Each connection is handled independently rather than through
structured concurrency

## Testing

Tested on fast machines where the race condition was reliably
reproducible. The crash no longer occurs.

## References

- [swift-nio#2637](https://github.com/apple/swift-nio/issues/2637) -
Known issue with async server channels and cancellation
- [Comment from NIO
maintainer](https://github.com/apple/swift-nio/issues/2637#issuecomment-1921317577)
- Recommends avoiding cancellation or using callback-based API

Fixes #635

---------

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2.5.3
2026-01-27 09:10:58 +00:00
Sébastien Stormacq 102f92aafb Fix race condition crash in LambdaRuntimeClient channel lifecycle (Bug #624) (#632)
This PR fixes a race condition in `LambdaRuntimeClient` that causes a
fatal crash when an old channel's `closeFuture` callback fires after a
new connection has been established. The fix adds proper channel
lifecycle tracking and replaces the fatal error with graceful handling.

## Problem

**Crash Location**: `LambdaRuntimeClient.swift:270` in `channelClosed()`

**Error Message**:
```
Fatal error: Invalid state: connected(SocketChannel { ... }), closed
```

**Root Cause**: Race condition where:
1. An old channel's `closeFuture` callback fires
2. AFTER a new connection has been established (`connectionState =
.connected`)
3. BUT `closingState` is `.closed` from a previous close operation
4. The code asserted this was impossible and crashed with `fatalError`

This can occur when:
- Network conditions cause delayed channel cleanup
- Connection is recycled quickly (old channel still closing while new
one connects)
- Timing issues between channel close callbacks and new connection
establishment

## Solution

### Key Changes

1. **Added channel identity tracking**:
   ```swift
   private var channelsBeingClosed: Set<ObjectIdentifier> = []
   ```
Tracks which channels are in the process of closing to distinguish old
channels from the current one.

2. **Enhanced `connectionWillClose()`**:
   - Marks channels as "being closed" using `ObjectIdentifier`
   - Adds logging when old channels close while new connection is active

3. **Rewrote `channelClosed()` with defensive logic**:
- **Early return for tracked old channels**: Handles them gracefully
without affecting current connection
- **Replaced `fatalError` with warning log**: The `(_, .closed)` case
now logs a warning instead of crashing
- **Channel identity checks**: Only transitions state if the closing
channel is the CURRENT channel
- **Removed unconditional state change**: Previously set
`connectionState = .disconnected` for ANY channel close, now only for
the current channel

### Why This Fixes the Bug

The fix addresses the race condition by:
- Distinguishing between "current channel closing" vs "old channel
closing"
- Handling old channel closes gracefully without crashing or corrupting
state
- Not overwriting connection state when old channels close
- Providing visibility through logging when the race condition occurs

## Changes

### Modified Files

- **Sources/AWSLambdaRuntime/HTTPClient/LambdaRuntimeClient.swift**
  - Added `channelsBeingClosed: Set<ObjectIdentifier>` property
  - Enhanced `connectionWillClose()` with channel tracking
  - Rewrote `channelClosed()` with defensive logic and identity checks
  - Replaced `fatalError` with warning log for unexpected states
  - Removed unconditional state change in `closeFuture` callback

**Lines Changed**: ~150 lines modified/added

**Backward Compatibility**:  Fully compatible, no API changes

## Testing

###  All Existing Tests Pass

```bash
swift test
# Result: 91 tests passed in 14 suites
```

All original functionality is preserved with no regressions.

### ⚠️ Note on Test Coverage

While we cannot reproduce the exact race condition from bug #624 in a
deterministic test (it requires specific network timing), the fix:
- Is logically sound for the described race condition
- Improves defensive programming around channel lifecycle
- Replaces a fatal crash with graceful handling + logging
- Should prevent the crash by properly tracking channel identity

## Related Issues

Fixes #624

---------

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2026-01-27 08:53:31 +00:00
Sébastien Stormacq 34e89b4027 Fix Test hangs in Lambda+LocalServer (#630) (#631)
# Fix test hangs caused by Pool cancellation race conditions

## Summary

This PR fixes two related race conditions in
`Lambda+LocalServer+Pool.swift` that were causing the test suite to hang
approximately 10% of the time.

## Problem

The test suite exhibited intermittent hangs (~10% frequency) due to two
bugs in the Pool implementation:

1. **Individual task cancellation bug**: When one task waiting for a
specific `requestId` was cancelled, the cancellation handler would
incorrectly cancel ALL waiting tasks instead of just the cancelled one.

2. **Server shutdown hang**: When the server shut down, waiting
continuations in the pools were never cancelled, causing handlers to
wait indefinitely for responses that would never arrive.

## Root Causes

### Root Cause #1: Cancellation Handler Removes ALL Continuations

The `onCancel` handler in `Pool._next()` was removing all continuations
from the `waitingForSpecific` dictionary when any single task was
cancelled:

```swift
onCancel: {
    // BUG: Removes ALL continuations, not just the cancelled task's
    for continuation in state.waitingForSpecific.values {
        toCancel.append(continuation)
    }
    state.waitingForSpecific.removeAll()
}
```

This caused unrelated concurrent invocations to fail with
`CancellationError` when one client cancelled their request.

### Root Cause #2: No Pool Cleanup During Server Shutdown

When the server shut down (e.g., test completes), the task group was
cancelled but the pools' waiting continuations were never notified. The
`/invoke` endpoint handlers would continue waiting for responses that
would never arrive because the Lambda function had stopped.

## Solution

### Fix #1: Only Remove Specific Continuation on Cancellation

Modified the cancellation handler to only remove the continuation for
the specific cancelled task:

```swift
onCancel: {
    // Only remove THIS task's continuation
    let continuationToCancel = self.lock.withLock { state -> CheckedContinuation<T, any Error>? in
        if let requestId = requestId {
            return state.waitingForSpecific.removeValue(forKey: requestId)
        } else {
            let cont = state.waitingForAny
            state.waitingForAny = nil
            return cont
        }
    }
    
    continuationToCancel?.resume(throwing: CancellationError())
}
```

### Fix #2: Add Pool Cleanup During Server Shutdown

Added `cancelAll()` method to the Pool class and call it during server
shutdown:

```swift
func cancelAll() {
    let continuationsToCancel = self.lock.withLock { state -> [CheckedContinuation<T, any Error>] in
        var toCancel: [CheckedContinuation<T, any Error>] = []
        
        if let continuation = state.waitingForAny {
            toCancel.append(continuation)
            state.waitingForAny = nil
        }
        
        for continuation in state.waitingForSpecific.values {
            toCancel.append(continuation)
        }
        state.waitingForSpecific.removeAll()
        
        return toCancel
    }
    
    for continuation in continuationsToCancel {
        continuation.resume(throwing: CancellationError())
    }
}
```

Called during server shutdown:

```swift
let serverOrHandlerResult1 = await group.next()!
group.cancelAll()

// Cancel all waiting continuations in the pools to prevent hangs
server.invocationPool.cancelAll()
server.responsePool.cancelAll()
```

## Changes

### Modified Files

- **Sources/AWSLambdaRuntime/HTTPServer/Lambda+LocalServer+Pool.swift**
- Fixed cancellation handler in `_next()` to only remove specific
continuation
  - Added `cancelAll()` method for server shutdown cleanup

- **Sources/AWSLambdaRuntime/HTTPServer/Lambda+LocalServer.swift**
  - Call `cancelAll()` on both pools during server shutdown

### New Files

- **Tests/AWSLambdaRuntimeTests/LocalServerPoolCancellationTests.swift**
  - Added comprehensive test suite with 3 tests
- `testCancellationOnlyAffectsOwnTask`: Verifies only the cancelled task
receives CancellationError
- `testConcurrentInvocationsWithCancellation`: Tests real-world scenario
with 5 concurrent invocations
- `testFIFOModeCancellation`: Ensures FIFO mode cancellation works
correctly

## Testing

### Before Fix
- Test suite hung ~10% of the time
- When 1 task was cancelled, all 5 concurrent tasks received
`CancellationError`
- Streaming tests would occasionally hang during shutdown

### After Fix
- All 91 tests pass consistently without hangs
- When 1 task is cancelled, only that specific task receives
`CancellationError`
- Other tasks continue waiting normally
- Server shutdown properly cleans up all waiting continuations
- Multiple consecutive test runs confirm stability

### Test Coverage

The new test suite reproduces both bugs and verifies the fixes:

1. **testCancellationOnlyAffectsOwnTask**: Creates 3 tasks waiting for
different requestIds, cancels only one, and verifies the others are not
affected
2. **testConcurrentInvocationsWithCancellation**: Simulates 5 concurrent
invocations with one cancellation
3. **testFIFOModeCancellation**: Tests FIFO mode to ensure it still
works correctly

---------

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2.5.2
2026-01-15 20:58:03 +01:00
Sébastien Stormacq feb6d2cd49 Cleanup script and test example (#628)
Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2026-01-13 11:46:00 +01:00
Sébastien Stormacq 61f392df7a Refactor LambdaRuntime (#627)
refcator to isolate the code in `startRuntimeInterfaceClient` and
`startLocalServer` functions
Also change the name of the global variable `_isRunning` to
`_isLambdaRuntimeRunning`

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2026-01-13 11:31:03 +01:00
Sébastien Stormacq 6d2c5bf91d Rename Lambda+JSON file (#626)
Rename Lambda+JSON file to LambdaRuntime+JSON, to prepare for furture
support of Lambda Managed Runtime

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2026-01-13 11:11:21 +01:00
Sébastien Stormacq 634c36e5d3 Lift up the trace limit on payload to make it actually useful when debugging (#625)
When using `trace` log level the runtime diplays 1Kb of the input
payload to help debugging cases where the JSON decoding fails. Most of
the type, this 1 Kb trace is not enough to understand what part of the
incoming JSON fails to decode.

This PR raises the limit to 6Mb to be actually useful.
2.5.1
2026-01-11 15:58:13 +01:00
Sébastien Stormacq 4b4054d1c4 Remove unnecessary Sendable constraint (#622)
This PR removes `Sendable` requirement on `StreamingClosureHandler `.

While analyzing code for the upcoming support of Lambda Managed Runtime,
I found out that `StreamingClosureHandler` has `Sendable` requirement,
which is not necessary.

Removing requirement doesn't require a major speed bump as the change is
compatible with existing code.
2.5.0
2026-01-01 11:33:12 -05:00
Sébastien Stormacq e0f064a93e Refactor project directories (#621)
This PR refactors the project's directories.
As the number of source files grows, I created subdirectories to
separate the runtime itself, from its HTTP Client (`RuntimeClient`) and
local HTTP Server (`Lambda+LocalServer`).

The new layout looks like this:

```text
Sources
├── AWSLambdaRuntime
│   ├── FoundationSupport
│   │   ├── Context+Foundation.swift
│   │   ├── Lambda+JSON.swift
│   │   └── Vendored
│   │       ├── ByteBuffer-foundation.swift
│   │       └── JSON+ByteBuffer.swift
│   ├── HTTPClient
│   │   ├── ControlPlaneRequest.swift
│   │   ├── ControlPlaneRequestEncoder.swift
│   │   ├── LambdaRuntimeClient+ChannelHandler.swift
│   │   ├── LambdaRuntimeClient.swift
│   │   └── LambdaRuntimeClientProtocol.swift
│   ├── HTTPServer
│   │   ├── Lambda+LocalServer+Pool.swift
│   │   └── Lambda+LocalServer.swift
│   ├── Lambda.swift
│   ├── LambdaClock.swift
│   ├── LambdaContext.swift
│   ├── LambdaRequestID.swift
│   ├── LambdaResponseStreamWriter+Headers.swift
│   ├── LambdaRuntimeError.swift
│   ├── Runtime
│   │   ├── LambdaHandlers.swift
│   │   ├── LambdaRuntime+Codable.swift
│   │   ├── LambdaRuntime+Handler.swift
│   │   ├── LambdaRuntime+ServiceLifecycle.swift
│   │   └── LambdaRuntime.swift
│   ├── SendableMetatype.swift
│   ├── Utils.swift
│   └── Version.swift
└── MockServer
    └── MockHTTPServer.swift
```
2026-01-01 11:19:13 -05:00
Adam Fowler 1f0888ee7b Fix after release of swift-log 1.8.0 (#619)
<!--- Provide a general summary of your changes in the Title above -->
Fix after release of swift-log 1.8.0
## Issue \#
<!--- If it fixes an issue, please link to the issue here -->

## Description of changes
<!--- Why is this change required? What problem does it solve? -->

## New/existing dependencies impact assessment, if applicable
<!--- No new dependencies were added to this change. -->
<!--- If any dependency was added / modified / removed,
THIRD-PARTY-LICENSES must be updated accordingly. -->

## Conventional Commits
<!--- Please use conventional commits to let us know what kind of change
this is.-->
<!--- More info can be found here:
https://www.conventionalcommits.org/en/v1.0.0/-->

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license.
2.4.1
2025-12-14 09:49:47 +01:00
Sébastien Stormacq 4494361efb Fix dependency on HB example (#618)
The Hummingbird-Lambda exports the Swift AWS Lambda Runtime. Therefore,
the sample project doesn't need to declare the runtime as a dependency.
2025-12-10 07:58:11 +01:00
Sébastien Stormacq 72865e405a Update commented deps in examples to use runtime v2 (#616)
Fix example dependencies

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-12-05 16:48:19 -08:00
Sébastien Stormacq 3ddd64087d Add Streaming Lambda Examples with API Gateway and Function URL (#615)
## Overview

This PR reorganizes and enhances the streaming Lambda examples by
splitting them into two distinct examples that demonstrate different
invocation methods:

1. **Streaming+FunctionUrl** - Streaming responses via Lambda Function
URLs
2. **Streaming+APIGateway** - Streaming responses via API Gateway REST
API

## Changes

### 🔄 Restructured Examples

- **Renamed**: `Examples/Streaming/` → `Examples/Streaming+FunctionUrl/`
  - Maintains the original streaming example using Lambda Function URLs
  - Updated documentation to clarify Function URL-specific configuration
  - Improved AWS credentials handling in curl examples

- **New**: `Examples/Streaming+APIGateway/`
- Comprehensive example demonstrating API Gateway REST API with response
streaming
- Complete SAM template with proper IAM roles and streaming
configuration
  - Detailed documentation covering API Gateway-specific setup

### 📚 Documentation Improvements

#### Streaming+FunctionUrl
- Clarified that this example uses Lambda Function URLs
- Updated curl examples to use `eval $(aws configure export-credentials
--format env)` for cleaner credential handling
- Maintained all existing functionality and deployment instructions

#### Streaming+APIGateway (New)
- **316-line comprehensive README** covering:
  - Response streaming concepts and benefits
  - HTTP status code and header configuration
  - Streaming response body patterns
  - Local testing instructions
  - Complete SAM deployment guide with detailed template explanation
  - API Gateway-specific invocation with AWS Sigv4 authentication
  - Payload format documentation with example JSON
  - Security and reliability best practices
  - How API Gateway streaming works under the hood

### 🛠️ Technical Details

#### API Gateway Streaming Configuration
The new example demonstrates:
- Special Lambda URI: `/response-streaming-invocations` endpoint
- `responseTransferMode: STREAM` configuration
- IAM role with both `lambda:InvokeFunction` and
`lambda:InvokeWithResponseStream` permissions
- Proper timeout configuration (60s) to accommodate streaming duration

#### SAM Template Features
```yaml
- Lambda function with streaming support (arm64, provided.al2)
- API Gateway REST API with OpenAPI 3.0 definition
- IAM execution role for API Gateway to invoke Lambda with streaming
- Complete outputs for easy testing (API URL and Lambda ARN)
```

### 🔐 Security Enhancements

Both examples now include comprehensive security best practices:
- API Gateway access logging
- Throttling configuration
- AWS WAF integration recommendations
- Lambda concurrent execution limits
- Environment variable encryption
- Dead Letter Queue (DLQ) configuration
- VPC configuration guidance

### 🧪 Testing

Both examples support:
- **Local testing**: `swift run` with curl invocation on port 7000
- **AWS deployment**: Complete SAM templates with deployment
instructions
- **Authenticated invocation**: AWS Sigv4 examples with proper
credential handling

## Benefits

1. **Clearer separation**: Developers can now easily choose between
Function URLs and API Gateway based on their use case
2. **Better documentation**: Each example has tailored documentation for
its specific invocation method
3. **Production-ready**: Includes security best practices and proper IAM
configuration
4. **Easier testing**: Improved credential handling in curl examples

## Breaking Changes

None - this is purely additive. The original streaming example is
preserved as `Streaming+FunctionUrl`.

## Testing Checklist

- [x] Local testing works for both examples
- [x] SAM deployment templates are valid
- [x] Documentation is comprehensive and accurate
- [x] Security best practices are documented
- [x] Curl examples work with proper authentication

## Related Documentation

- [AWS Lambda Response
Streaming](https://docs.aws.amazon.com/lambda/latest/dg/configuration-response-streaming.html)
- [API Gateway Lambda Proxy Integration with
Streaming](https://docs.aws.amazon.com/apigateway/latest/developerguide/response-streaming-lambda-configure.html)
- [Lambda Function
URLs](https://docs.aws.amazon.com/lambda/latest/dg/lambda-urls.html)
EOF

---------

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-12-05 16:38:50 -08:00
Sébastien Stormacq a590d08818 Use Swiftlang's github action for unit tests (#614)
Remove a dependency on Swift NIO's GitHub workflows and use Swiftlang's
github action for unit tests instead

---------

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-11-30 19:52:23 +01:00
Sébastien Stormacq 9f9434bfa4 Use Swiftlang's GitHUb workflow for testing with Static SDK (#613)
Use Swiftlang's GitHub workflow script to test with the static SDK

---------

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-11-30 19:17:31 +01:00
Sébastien Stormacq 023b8fe526 Simplify local dependency injection for examples (#612)
See issue #536 

All the examples are now depending on the runtime library located at
`../..`. The `Package.swift` files contain a commented line with the
`.package` to use when user wants to fetch the runtime from GitHub.

---------

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-11-30 18:48:06 +01:00
Sébastien Stormacq fb31389f88 Fix 565 : HelloWorld and Resource examples now uses Swift 6.2 (#611)
See issues #565 
HelloWorld and Resources examples project now use Swift 6.2

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-11-30 12:12:34 +01:00
Sébastien Stormacq 437835530a fix #609 : [plugin] Update the README and the doc to mention potential credentials error when using the plugin. (#610)
## Description

Adds documentation for Docker credential store errors that users may
encounter when running `swift package archive
--allow-network-connections docker`.

## Changes

- Added a note in `readme.md` explaining how to resolve Docker
credential store errors
- Added a note in `Sources/AWSLambdaRuntime/Docs.docc/Deployment.md`
with the same guidance

## Problem

Users may encounter authentication errors when the Swift package plugin
attempts to pull Docker images, particularly when Docker is configured
with a credential store (e.g., `docker-credential-desktop`). This issue
is documented in #609.

## Solution

The documentation now provides two workarounds:
1. Remove the `credsStore` entry from `~/.docker/config.json`
2. Use the `--disable-sandbox` flag with the archive command

Both notes link to issue #609 for additional context and discussion.

## Related Issue

Fixes #609
2025-11-28 08:25:16 +01:00
Sébastien Stormacq 2abe7eb7de Add support for Lambda Tenants (#608)
Address https://github.com/awslabs/swift-aws-lambda-runtime/issues/605

NEW Lambda Tenant isolation capability: 
https://docs.aws.amazon.com/lambda/latest/dg/tenant-isolation.html 


# Add Support for Lambda Tenant Isolation Mode

## Summary

This PR adds support for AWS Lambda's tenant isolation mode to the Swift
AWS Lambda Runtime, enabling developers to build multi-tenant
applications with strict execution environment isolation per tenant.

## Changes

### Runtime Support
- Added `tenantID` property to `LambdaContext` to expose the tenant
identifier
- Extended `InvocationMetadata` to capture the
`Lambda-Runtime-Aws-Tenant-Id` header
- Added `AmazonHeaders.tenantID` constant for the tenant ID header
- Added trace logging for invocation headers to aid debugging

### New Example: MultiTenant
A complete working example demonstrating tenant isolation mode:
- **Request tracking system** that maintains separate counters and
histories per tenant
- **Actor-based storage** (`TenantDataStore`) for thread-safe tenant
data management
- **Immutable data structures** (`TenantData`) following Swift best
practices
- **API Gateway integration** with tenant ID passed via query parameter
- **SAM template** configured with `TenancyConfig.TenantIsolationMode:
PER_TENANT`
- **Comprehensive documentation** covering architecture, deployment,
testing, and best practices

### Testing
- Added unit test for tenant ID extraction from invocation headers
- Integrated MultiTenant example into CI/CD pipeline

### Documentation
The example includes detailed documentation on:
- When to use tenant isolation (user code execution, sensitive data
processing)
- How tenant isolation works (dedicated environments, no cross-tenant
reuse)
- Concurrency limits and scaling considerations
- Pricing implications
- Security best practices
- CloudWatch monitoring with tenant dimensions

## Files Changed
- `Sources/AWSLambdaRuntime/LambdaContext.swift` - Added tenantID
property
- `Sources/AWSLambdaRuntime/ControlPlaneRequest.swift` - Capture tenant
ID from headers
- `Sources/AWSLambdaRuntime/Utils.swift` - Added tenantID header
constant
- `Sources/AWSLambdaRuntime/Lambda.swift` - Pass tenant ID to context
- `Sources/AWSLambdaRuntime/LambdaRuntimeClient+ChannelHandler.swift` -
Added trace logging
- `Tests/AWSLambdaRuntimeTests/InvocationTests.swift` - Added tenant ID
test
- `Examples/MultiTenant/*` - New complete example with SAM template
- `.github/workflows/pull_request.yml` - Added MultiTenant to CI
pipeline

## Testing Instructions

1. Build and deploy the example:
   bash
  cd Examples/MultiTenant
  swift package archive --allow-network-connections docker
  sam deploy --guided
  

2. Test with different tenants:
   bash
curl
"https://<api-id>.execute-api.<region>.amazonaws.com/Prod?tenant-id=
alice"
curl
"https://<api-id>.execute-api.<region>.amazonaws.com/Prod?tenant-id=
bob"
  


3. Verify isolation by checking that each tenant maintains separate
request counts

## Related Documentation
- [AWS Lambda Tenant
Isolation](https://docs.aws.amazon.com/lambda/latest/dg/tenant-isolation.html)
- [AWS Blog: Streamlined Multi-Tenant Application
Development](https://aws.amazon.com/blogs/aws/streamlined-multi-tenant-application-development-with-tenant-isolation-mode-in-aws-lambda/)

---------

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
Co-authored-by: Tim Condon <0xTim@users.noreply.github.com>
2.4.0
2025-11-21 21:14:15 +01:00
Sébastien Stormacq 0305cb31b8 Add scripts to measure cold start performance (#604)
I added two shell scripts under `scripts/lambda-performance` to help
measure Lambda cold and warm start time.

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-11-19 20:36:51 +01:00
Sébastien Stormacq 85bd29e4de Makes performance script run on macOS (#603)
By default, the script started the MockServer on port 7000, which is
used by AirPlay on macOS.
This caused conflicts.

I also made a minor change on the logging to avoir reporting an error
when the server closes the connection.
2025-11-16 21:02:15 +01:00
Sébastien Stormacq 1b3c81c51f Add Swift ServiceLifecycle section to the readme (#601)
Add Swift ServiceLifecycle section to the readme

---------

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-11-03 12:16:36 +01:00
Sébastien Stormacq 76c272edba Fix broken links (#600)
This PR fixes broken links in the README and add a link to the project
incubation process of the SSWG and to the repo GitHub issues.

---------

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-11-03 11:52:52 +01:00
Sébastien Stormacq 97583a78c2 Add Multi-Source API Example (#598)
This PR adds a new example demonstrating how to build a Lambda function
that handles requests from multiple sources (Application Load Balancer
and API Gateway V2) using a single handler.

### What's New

**New Example: `Examples/MultiSourceAPI`**

A Lambda function that:
- Implements `StreamingLambdaHandler` to accept raw `ByteBuffer` events
- Dynamically decodes events as either `ALBTargetGroupRequest` or
`APIGatewayV2Request`
- Returns appropriate responses based on the detected event source
- Demonstrates handling multiple AWS service integrations with a single
function

### Key Features

- **Type-safe event detection**: Uses Swift's `Decodable` to identify
the event source at runtime
- **Streaming response**: Implements `StreamingLambdaHandler` for
efficient response handling
- **Complete deployment**: Includes SAM template with both ALB and API
Gateway V2 infrastructure
- **Production-ready**: Full VPC setup with subnets, security groups,
and load balancer configuration

### Files Added

- `Examples/MultiSourceAPI/Sources/main.swift` - Lambda handler
implementation
- `Examples/MultiSourceAPI/Package.swift` - Swift package configuration
- `Examples/MultiSourceAPI/template.yaml` - SAM deployment template with
ALB and API Gateway V2
- `Examples/MultiSourceAPI/README.md` - Documentation with build,
deploy, and test instructions
- Updated CI to include the new example

### Use Case

This pattern is useful when you want to:
- Expose the same Lambda function through multiple AWS services
- Reduce code duplication by handling similar requests from different
sources
- Maintain a single codebase for multi-channel APIs

---------

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
Co-authored-by: Josh Elkins <jbelkins@users.noreply.github.com>
2025-11-02 21:58:02 +01:00
Sébastien Stormacq 5c7a55500c Fix typo in readme (#599)
Fix typo in TL;DR instructions to setup a new Lambda project.

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-11-02 21:35:56 +01:00
Sébastien Stormacq f5e534cae2 fix more links (#597)
Fix addition links and replace /swift-server to /awslabs

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-10-30 11:24:19 +01:00
Sébastien Stormacq b1553d2766 Accept multiple POST /invoke requests to allow parallel testing (#585)
Closing
https://github.com/swift-server/swift-aws-lambda-runtime/issues/584

The LocalServer now queues concurrent `POST /invoke` requests from
testing client applications and ensures that the requests are delivered
to the Lambda Runtime one by one, just like the AWS Lambda Runtime
environment does.

The `Pool` has now two modes : pure FIFO (one element get exactly one
`next()`) and one mode where multiple elements can get pushed and
multiple `next(for requestId:String)` can be called concurrently.

The two modes are needed because invocations are 1:1 (one `POST /invoke`
is always by one matching `GET /next`) but responses are n:n (a response
can have multiple chunks and concurrent invocations can trigger multiple
`next(for requestId: String)`

I made a couple of additional changes while working on this PR 

- I moved the `Pool` code in a separate file for improved readability 

- I removed an instance of `DispatchTime` that was hiding in the code,
unnoticed until today

- I removed the `async` requirement on `Pool.push(_)` function. This was
not required (thank you @t089 for having reported this)

- I removed the `fatalError()` that was in the `Pool` implementation.
The pool now throws an error when `next()` is invoked concurrently,
making it easier to test.

- I added extensive unit tests to validate the Pool behavior 

- I added a test to verify that a rapid succession of client invocations
are correctly queued and return no error

- I moved a `continuation(resume:)` outside of a lock. Generally
speaking, it's a bad idea to resume continuation while owning a lock. I
suspect this is causing a error during test execution when we spawn and
tear down mutliple `Task` very quickly. In some rare occasions, the test
was failing with an invalid assertion in NIO :
`NIOCore/NIOAsyncWriter.swift:177: Fatal error: Deinited NIOAsyncWriter
without calling finish()`

---------

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2.3.1
2025-10-22 07:52:31 +02:00
Sébastien Stormacq e58d89148c Replace standard documents and processes with AWS ones (#574)
- Adjust notice, security reporting, code of conduct, contribution
process to the standard AWS documents
- Adjust GitHub issue templates to AWS standard ones.
- Adjust the license header in all source files

---------

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-10-21 23:27:30 +02:00
Sébastien Stormacq 007ac1f192 [ci] Use APIGatewayV2 for link foundation check (#595)
Revert change on
https://github.com/awslabs/swift-aws-lambda-runtime/pull/593

The root cause has been addressed in the Swift AWS Lambda Event library 
https://github.com/awslabs/swift-aws-lambda-events/pull/99

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-10-21 06:52:35 +02:00
Sébastien Stormacq 8168a5c22e fix ci : check libFoundation on HelloWorld example (#593)
Fix errors in the CI
The script that checks the presence of `libFoundation` in the binary
started to fail.
I can't think about a recent change that would cause this.

This PR change the test script to use the `HelloWorld` example instead
of `APIGAtewayV2`

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-10-20 20:01:46 +02:00
Sébastien Stormacq dee635267b change references from /swift-server to /awslabs (#591)
Change Examples, README, and doc to refer to https://github.org/awslabs
instead of https://github.org/swift-server

---------

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-10-17 16:46:58 +02:00
Sébastien Stormacq 8116ba3023 Allow multiple invocations of streaming Lambda functions with the local test server (#590)
The Local HTTP Server (used when testing) used to block after one
invocation of a streaming lambda function. Now you can invoke multiple
times your streaming function without having to restart the local HTTP
server.

### Motivation:

Bug https://github.com/swift-server/swift-aws-lambda-runtime/issues/588

### Modifications:

The flow to respond to streaming and non-streaming requests are
different. In the streaming request flow, we forgot to send an 202
accept response to the lambda runtime client after it posted the end
chunck of the response (in other words, `POST /response` never received
an HTTP 202 response.) This caused the Lambda Runtime to hang and never
issue the next `GET /next `request.

### Result:

You can now send multiple invocations to your streaming lambda.

---------

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-10-17 10:37:38 +02:00
Natan Rolnik e3b74f3a0e Add initializer with LambdaHandler directly with Decodable event and Void output (#589)
_Add convenience initializer for `LambdaRuntime` to accept
`LambdaHandler` instances with `Void` output_

### Motivation:

Following PR #581, which added convenience initializers for
`LambdaRuntime` to accept `LambdaHandler` instances with `Encodable`
outputs, there was still a gap for handlers that return `Void`. This is
useful, for example, for AWS event sources like SQS, where the
`AWSLambdaEvents` package provides `SQSEvent` but there's no
corresponding output type - handlers simply process messages and return
`Void`.

Without this initializer, developers had to manually wrap their handlers
with `LambdaCodableAdapter` and `LambdaHandlerAdapter`, which was
verbose and inconsistent with the new API (similar to what is described
in #581)

### Modifications:

1. Added a new `init(decoder:handler:)` convenience initializer to
`LambdaCodableAdapter` in `Lambda+JSON.swift` that accepts a
`JSONDecoder` for handlers with `Void` output.

2. Added a new convenience initializer to `LambdaRuntime` that accepts a
`LambdaHandler` instance with `Void` output directly, handling the
wrapping internally.

3. Updated documentation comments to distinguish between handlers with
`Void` and `Encodable` outputs.

### Result:

Developers can now initialize `LambdaRuntime` with handlers that return
`Void` using a clean, direct API. This is especially useful for event
sources like SQS:

```swift
import AWSLambdaEvents

struct MySQSHandler: LambdaHandler {
    func handle(_ event: SQSEvent, context: LambdaContext) async throws {
        // Process SQS messages
    }
}

let runtime = LambdaRuntime(lambdaHandler: MySQSHandler())
```

This provides API completeness, matching the convenience initializers
for handlers with `Encodable` outputs, and delivers better ergonomics
for common serverless patterns.
2.3.0
2025-10-16 21:34:49 +02:00
Ben Rosen 9487a09e3a Lambda Handler errors now reports the root error in field errorType rather than "FunctionError" constant (#587)
### Motivation:

Fix for Issue
[#580](https://github.com/swift-server/swift-aws-lambda-runtime/issues/580),
by making it so that the `errorType` in failed requests will be the type
of the error entity, rather than a hardcoded string of `FunctionError`.
This allows orchestration within step functions that perform retry/catch
logic based on different error output types.

### Modifications:

At a high level, the issue is that swift-aws-lambda-runtime, when an
error is thrown, outputs the errorType as hardcoded to FunctionError.
You can see that
[here](https://github.com/swift-server/swift-aws-lambda-runtime/blob/main/Sources/AWSLambdaRuntime/LambdaRuntimeClient%2BChannelHandler.swift#L337):

```
let errorResponse = ErrorResponse(errorType: Consts.functionError, errorMessage: "\(error)")
```

This PR changes this for all cases to output the type of the error,
rather than the hardcoded string:
```
let errorResponse = ErrorResponse(errorType: "\(type(of: error))", errorMessage: "\(error)")
```
Now, I will show 2 examples with this solution:
```
let runtime = LambdaRuntime {
    (event: Input, context: LambdaContext) in

    enum MyTestErrorType: Error {
        case testError
    }
    
    throw MyTestErrorType.testError
}

// outputs {"errorType":"MyTestErrorType","errorMessage":"testError"}
```
```
let dynamoDB: DynamoDB = DynamoDB(client: .init())

let runtime = LambdaRuntime {
    (event: Input, context: LambdaContext) in

    let _ = try await dynamoDB.putItem(DynamoDB.PutItemInput(item: [:], tableName: ""))
    
    return Output()
}

// outputs {"errorType":"AWSClientError","errorMessage":"ValidationError: Length of PutItemInput.tableName (0) is less than minimum allowed value 1."}
```
2.2.0
2025-10-15 00:30:40 +02:00
Sébastien Stormacq 22f9f6d5e7 Double time interval to allow test to succeed on slow machines (#583)
See https://github.com/swift-server/swift-aws-lambda-runtime/issues/582

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2.1.1
2025-10-13 19:40:44 +02:00
Natan Rolnik 461c18af6f Add LambdaRuntime initializer with LambdaHandler directly with Codable support (#581)
_Add convenience initializer for `LambdaRuntime` to accept
`LambdaHandler` instances directly_

### Motivation:

When using the Swift AWS Lambda Runtime with custom handler types that
conform to `LambdaHandler`, developers previously had two options to
initialize `LambdaRuntime`:

1. Manually wrap their handler with `LambdaCodableAdapter` and
`LambdaHandlerAdapter`:
   ```swift
   let lambdaHandler = MyHandler()
   let handler = LambdaCodableAdapter(
       encoder: JSONEncoder(),
       decoder: JSONDecoder(),
       handler: LambdaHandlerAdapter(handler: lambdaHandler)
   )
   let runtime = LambdaRuntime(handler: handler)
   ```

2. Use a closure-based initializer that indirectly calls the handler:
   ```swift
   let lambdaHandler = MyHandler()
   let runtime = LambdaRuntime { event, context in
       try await lambdaHandler.handle(event, context: context)
   }
   ```

Both approaches are verbose and don't provide a clean, ergonomic API for
the common case of initializing `LambdaRuntime` with a custom
`LambdaHandler` instance. The closure approach also creates an
unnecessary indirection layer, wrapping the handler in a
`ClosureHandler` before adapting it, or using `LambdaCodableAdapter`.

### Modifications:

Added a new convenience initializer to `LambdaRuntime` in
`Lambda+JSON.swift` that accepts a `LambdaHandler` instance directly:

```swift
public convenience init<Event: Decodable, Output, LHandler: LambdaHandler>(
    decoder: JSONDecoder = JSONDecoder(),
    encoder: JSONEncoder = JSONEncoder(),
    logger: Logger = Logger(label: "LambdaRuntime"),
    lambdaHandler: sending LHandler
)
where
    Handler == LambdaCodableAdapter<
        LambdaHandlerAdapter<Event, Output, LHandler>,
        Event,
        Output,
        LambdaJSONEventDecoder,
        LambdaJSONOutputEncoder<Output>
    >,
    LHandler.Event == Event,
    LHandler.Output == Output
```

This initializer handles the wrapping of the `LambdaHandler` with the
necessary adapters internally, matching the pattern already established
for closure-based handlers.

### Result:

Developers can now initialize `LambdaRuntime` with a `LambdaHandler`
instance using a clean, direct API:

```swift
let lambdaHandler = MyHandler()
let runtime = LambdaRuntime(lambdaHandler: lambdaHandler)
```

This provides:
- **Better ergonomics**: More intuitive and less verbose API
- **Consistency**: Matches the pattern of accepting handlers directly,
similar to how `StreamingLambdaHandler` can be used
- **No extra indirection**: Avoids wrapping the handler in an
unnecessary `ClosureHandler` or `LambdaCodableAdapter`
- **Type safety**: Maintains full type inference for `Event` and
`Output` types from the handler
2.1.0
2025-10-09 19:20:19 +02:00
Sébastien Stormacq eeb354986b Remove links to runtime v1, add links to the doc on SPI (#576)
- Remove links to runtime v1,
- add links to the doc on the Swift package Index
2025-09-30 11:51:52 +02:00
Sébastien Stormacq 8cfd36a30d Rename APIGateway example to APIGatewayV2 (#575)
Now that we have an APIGatewayV1 example, rename the existing APIGateway
examples to APIGatewayV2.

Fix https://github.com/transfer-aws/swift-aws-lambda-runtime/issues/572
2.0.0
2025-09-29 10:37:30 +02:00
Sébastien Stormacq 74e4efdbac Apply recommendation for security and reliability (#573)
Apply recommendations in code and documentation

- [CI] restrict permissions to read-all instead of the default write-all
- All examples README.md : add a note about Lambda functions
configuration with improved security and scalability changes for
production environment
- Swift docc documentation: add a note about Lambda functions
configuration with improved security and scalability changes for
production environment

---------

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-09-27 12:39:16 +02:00
Erin Sparling d8aa38be78 [Example] Add APIGatewayV1 example (#569)
This PR adds an APIGateway V1 example, which differs slightly from the
existing [V2
example](https://github.com/swift-server/swift-aws-lambda-runtime/tree/main/Examples/APIGateway).

### Motivation:

While APIGatewayV2 has existed for a while, there are still some
scenarios where V1 is preferable (see [Choose between REST APIs and HTTP
APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-vs-rest.html)
for more details). This PR adds a working example for the `Api` endpoint
type.

### Modifications:

Sources/main.swift
- Swapped APIGatewayRequestV2 and APIGatewayResponseV2 for their
unversioned counterparts (aka V1).

template.yaml
- Changed the Events name and corresponding `Type: Api` values.
- Added necessary additional properties to define a `GET` endpoint for
an `Api` endpoint.

Readme.md
- Updated the request and response example outputs.

### Result:

Now, an APIGateway and APIGatewayV1 example exist. 

> [!NOTE]
> It is the author's opinion that this new example should technically be
called `APIGateway` and the existing one should be renamed to
`APIGatewayV2` to keep consistent with the request and response type
naming conventions, but this is omitted from this request to be less
disruptive.
2025-09-26 12:13:48 +00:00
Sébastien Stormacq 02d483074d [Example] Use smaller containers in all examples (#571)
All the examples using SAM have a default Lambda runtime environment
memory size of 512Mb.

Lambda functions run in a microVM defined by its memory size. The memory
size influences the CPU power.
(see
https://docs.aws.amazon.com/lambda/latest/dg/configuration-memory.html)

Increasing memory size increases runtime performance but also increase
costs.

As most of our examples are very simple and small functions, 512Mb
memory is not required. This PR reduces Lambda runtime execution
environment to 128Mb to reduce AWS costs.

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
2025-09-26 10:10:12 +02:00
Sébastien Stormacq a1ab8df708 Update toolchain and doc for 6.2 (#564)
In preparation for the 2.0.0 GA release,

- Update `.swift-version`, `Package.swift` and all examples'
`package.swift` to Swift 6.2
- Update all references to `2.0.0-beta.3` to `2.0.0`. This includes the
doc and readme, but also the dependencies in the examples
`Package.swift`. This will temporary break the build of the examples,
until we tag v2.0.0. Note the CI will not be affected as its consumes
the local version of the library
- [CI] Use Swift-6.2-noble for all testing tasks
- Reinstate the script to generate the contributors list and update the
list
2.0.0-rc.1
2025-09-23 21:12:33 +02:00
Sébastien Stormacq 1843cdcb3c [fix] The library must compile when no traits are enabled (#563)
Make required changed to ensure the library compiles when no traits are
enabled (fix:
https://github.com/swift-server/swift-aws-lambda-runtime/issues/562)

Add an example project that serves as test in the CI

### Motivation:

Recent changes introduced compilation errors when no traits are enabled.

### Modifications:

- `LambdaResponseStreamWriter.writeStatusAndHeaders()` moved to the
`FoundationSupport` directory where all classes and struct depending on
`Encodable` and `Decodable` are located, protected by `#if
FoundationJSONSupport`
- `LambdaRuntime.run()` method when ServiceLifeCycle is disabled in now
public (and therefore can not be `@inlinable` anymore)
- Add an example that disables all traits.
- Add this example to the CI 

### Result:

The Library now compiles when no default traits are enabled.
This is flagged `semver/major` because we change the public API
`LambdaRuntime.run()`
2025-09-16 11:05:45 +02:00
Sébastien Stormacq 303559d9ed Bump Amazon RDS version 19 PG 17 (#561)
Update SwiftServiceLifeCycle example to use Postgres 17 (PG 15 is going
to be deprecated on Amazon RDS)
2025-09-06 10:14:03 +02:00
Fabian Fett 191e27b0a0 Fix compile on macOS (#559)
We need to require ServiceLifecycle 2.8.0.
2025-09-04 15:24:15 +02:00
Sébastien Stormacq d8ee71fc09 add support for LOCAL_LAMBDA_PORT / HOST(#557)
Allows users to define on which port the Local server listens to, using
the `LOCAL_LAMBDA_PORT` environment variable.

While being at it, I also added `LOCAL_LAMBDA_HOST` if the user wants to
bind on a specific IP address.

I renamed `LOCAL_LAMBDA_SERVER_INVOCATION_ENDPOINT` to
`LOCAL_LAMBDA_INVOCATION_ENDPOINT` for consistency.

### Motivation:

Addresses
https://github.com/swift-server/swift-aws-lambda-runtime/issues/556

### Modifications:

- When run outside of the Lambda execution environment, check for the
value of `LOCAL_LAMBDA_PORT` and passes it down to the Lambda HTTP Local
Server and runtime client.

- Add a unit test 

### Result:

```
LAMBDA_USE_LOCAL_DEPS=../.. LOCAL_LAMBDA_PORT=8888 swift run                  

2025-09-01T21:55:22+0200 info LambdaRuntime: host="127.0.0.1" port=8888 [AWSLambdaRuntime] Server started and listening
```
2.0.0-beta.3
2025-09-03 18:22:57 +02:00