Skip to content

Remove "New" prefix from v2 additions #357

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

Merged
merged 2 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/AWSLambdaRuntime/Context+Foundation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import AWSLambdaRuntimeCore

import struct Foundation.Date

extension NewLambdaContext {
extension LambdaContext {
var deadlineDate: Date {
let secondsSinceEpoch = Double(Int64(bitPattern: self.deadline.rawValue)) / -1_000_000_000
return Date(timeIntervalSince1970: secondsSinceEpoch)
Expand Down
10 changes: 5 additions & 5 deletions Sources/AWSLambdaRuntime/Lambda+Codable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,13 @@ extension LambdaCodableAdapter {
}
}

extension NewLambdaRuntime {
/// Initialize an instance with a ``NewLambdaHandler`` defined in the form of a closure **with a non-`Void` return type**.
extension LambdaRuntime {
/// Initialize an instance with a ``LambdaHandler`` defined in the form of a closure **with a non-`Void` return type**.
/// - Parameter body: The handler in the form of a closure.
/// - Parameter encoder: The encoder object that will be used to encode the generic ``Output`` into a ``ByteBuffer``. ``JSONEncoder()`` used as default.
/// - Parameter decoder: The decoder object that will be used to decode the incoming ``ByteBuffer`` event into the generic ``Event`` type. ``JSONDecoder()`` used as default.
package convenience init<Event: Decodable, Output>(
body: @escaping (Event, NewLambdaContext) async throws -> Output,
body: @escaping (Event, LambdaContext) async throws -> Output,
encoder: JSONEncoder = JSONEncoder(),
decoder: JSONDecoder = JSONDecoder()
)
Expand All @@ -94,11 +94,11 @@ extension NewLambdaRuntime {
self.init(handler: handler)
}

/// Initialize an instance with a ``NewLambdaHandler`` defined in the form of a closure **with a `Void` return type**.
/// Initialize an instance with a ``LambdaHandler`` defined in the form of a closure **with a `Void` return type**.
/// - Parameter body: The handler in the form of a closure.
/// - Parameter decoder: The decoder object that will be used to decode the incoming ``ByteBuffer`` event into the generic ``Event`` type. ``JSONDecoder()`` used as default.
package convenience init<Event: Decodable>(
body: @escaping (Event, NewLambdaContext) async throws -> Void,
body: @escaping (Event, LambdaContext) async throws -> Void,
decoder: JSONDecoder = JSONDecoder()
)
where
Expand Down
8 changes: 4 additions & 4 deletions Sources/AWSLambdaRuntimeCore/ControlPlaneRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,19 @@ package struct InvocationMetadata: Hashable {
package let clientContext: String?
package let cognitoIdentity: String?

package init(headers: HTTPHeaders) throws(NewLambdaRuntimeError) {
package init(headers: HTTPHeaders) throws(LambdaRuntimeError) {
guard let requestID = headers.first(name: AmazonHeaders.requestID), !requestID.isEmpty else {
throw NewLambdaRuntimeError(code: .nextInvocationMissingHeaderRequestID)
throw LambdaRuntimeError(code: .nextInvocationMissingHeaderRequestID)
}

guard let deadline = headers.first(name: AmazonHeaders.deadline),
let unixTimeInMilliseconds = Int64(deadline)
else {
throw NewLambdaRuntimeError(code: .nextInvocationMissingHeaderDeadline)
throw LambdaRuntimeError(code: .nextInvocationMissingHeaderDeadline)
}

guard let invokedFunctionARN = headers.first(name: AmazonHeaders.invokedFunctionARN) else {
throw NewLambdaRuntimeError(code: .nextInvocationMissingHeaderInvokeFuctionARN)
throw LambdaRuntimeError(code: .nextInvocationMissingHeaderInvokeFuctionARN)
}

self.requestID = requestID
Expand Down
35 changes: 34 additions & 1 deletion Sources/AWSLambdaRuntimeCore/Lambda.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//

import Dispatch
import Logging
import NIOCore
import NIOPosix
Expand All @@ -28,7 +29,39 @@ import ucrt
#error("Unsupported platform")
#endif

enum Lambda {}
enum Lambda {
package static func runLoop<RuntimeClient: LambdaRuntimeClientProtocol, Handler>(
runtimeClient: RuntimeClient,
handler: Handler,
logger: Logger
) async throws where Handler: StreamingLambdaHandler {
var handler = handler

while !Task.isCancelled {
let (invocation, writer) = try await runtimeClient.nextInvocation()

do {
try await handler.handle(
invocation.event,
responseWriter: writer,
context: LambdaContext(
requestID: invocation.metadata.requestID,
traceID: invocation.metadata.traceID,
invokedFunctionARN: invocation.metadata.invokedFunctionARN,
deadline: DispatchWallTime(millisSinceEpoch: invocation.metadata.deadlineInMillisSinceEpoch),
logger: logger
)
)
} catch {
try await writer.reportError(error)
continue
}
}
}

/// The default EventLoop the Lambda is scheduled on.
package static var defaultEventLoop: any EventLoop = NIOSingletons.posixEventLoopGroup.next()
}

// MARK: - Public API

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import NIOCore

/// Lambda runtime context.
/// The Lambda runtime generates and passes the `LambdaContext` to the Lambda handler as an argument.
package struct NewLambdaContext: CustomDebugStringConvertible, Sendable {
package struct LambdaContext: CustomDebugStringConvertible, Sendable {
final class _Storage: Sendable {
let requestID: String
let traceID: String
Expand Down Expand Up @@ -127,8 +127,8 @@ package struct NewLambdaContext: CustomDebugStringConvertible, Sendable {
invokedFunctionARN: String,
timeout: DispatchTimeInterval,
logger: Logger
) -> NewLambdaContext {
NewLambdaContext(
) -> LambdaContext {
LambdaContext(
requestID: requestID,
traceID: traceID,
invokedFunctionARN: invokedFunctionARN,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ package protocol StreamingLambdaHandler {
/// - event: The invocation's input data.
/// - responseWriter: A ``LambdaResponseStreamWriter`` to write the invocation's response to.
/// If no response or error is written to `responseWriter` an error will be reported to the invoker.
/// - context: The ``NewLambdaContext`` containing the invocation's metadata.
/// - context: The ``LambdaContext`` containing the invocation's metadata.
/// - Throws:
/// How the thrown error will be handled by the runtime:
/// - An invocation error will be reported if the error is thrown before the first call to
Expand All @@ -39,7 +39,7 @@ package protocol StreamingLambdaHandler {
mutating func handle(
_ event: ByteBuffer,
responseWriter: some LambdaResponseStreamWriter,
context: NewLambdaContext
context: LambdaContext
) async throws
}

Expand All @@ -64,7 +64,7 @@ package protocol LambdaResponseStreamWriter {
///
/// - note: This handler protocol does not support response streaming because the output has to be encoded prior to it being sent, e.g. it is not possible to encode a partial/incomplete JSON string.
/// This protocol also does not support the execution of background work after the response has been returned -- the ``LambdaWithBackgroundProcessingHandler`` protocol caters for such use-cases.
package protocol NewLambdaHandler {
package protocol LambdaHandler {
/// Generic input type.
/// The body of the request sent to Lambda will be decoded into this type for the handler to consume.
associatedtype Event: Decodable
Expand All @@ -75,12 +75,12 @@ package protocol NewLambdaHandler {
/// Implement the business logic of the Lambda function here.
/// - Parameters:
/// - event: The generic ``Event`` object representing the invocation's input data.
/// - context: The ``NewLambdaContext`` containing the invocation's metadata.
/// - context: The ``LambdaContext`` containing the invocation's metadata.
/// - Returns: A generic ``Output`` object representing the computed result.
func handle(_ event: Event, context: NewLambdaContext) async throws -> Output
func handle(_ event: Event, context: LambdaContext) async throws -> Output
}

/// This protocol is exactly like ``NewLambdaHandler``, with the only difference being the added support for executing background
/// This protocol is exactly like ``LambdaHandler``, with the only difference being the added support for executing background
/// work after the result has been sent to the AWS Lambda control plane.
/// This is achieved by not having a return type in the `handle` function. The output is instead written into a
/// ``LambdaResponseWriter``that is passed in as an argument, meaning that the ``handle(_:)`` function is then free to implement
Expand All @@ -98,11 +98,11 @@ package protocol LambdaWithBackgroundProcessingHandler {
/// - event: The generic ``Event`` object representing the invocation's input data.
/// - outputWriter: The writer to send the computed response to. A call to `outputWriter.write(_:)` will return the response to the AWS Lambda response endpoint.
/// Any background work can then be executed before returning.
/// - context: The ``NewLambdaContext`` containing the invocation's metadata.
/// - context: The ``LambdaContext`` containing the invocation's metadata.
func handle(
_ event: Event,
outputWriter: some LambdaResponseWriter<Output>,
context: NewLambdaContext
context: LambdaContext
) async throws
}

Expand All @@ -121,67 +121,67 @@ package protocol LambdaResponseWriter<Output> {
/// A ``StreamingLambdaHandler`` conforming handler object that can be constructed with a closure.
/// Allows for a handler to be defined in a clean manner, leveraging Swift's trailing closure syntax.
package struct StreamingClosureHandler: StreamingLambdaHandler {
let body: @Sendable (ByteBuffer, LambdaResponseStreamWriter, NewLambdaContext) async throws -> Void
let body: @Sendable (ByteBuffer, LambdaResponseStreamWriter, LambdaContext) async throws -> Void

/// Initialize an instance from a handler function in the form of a closure.
/// - Parameter body: The handler function written as a closure.
package init(
body: @Sendable @escaping (ByteBuffer, LambdaResponseStreamWriter, NewLambdaContext) async throws -> Void
body: @Sendable @escaping (ByteBuffer, LambdaResponseStreamWriter, LambdaContext) async throws -> Void
) {
self.body = body
}

/// Calls the provided `self.body` closure with the ``ByteBuffer`` invocation event, the ``LambdaResponseStreamWriter``, and the ``NewLambdaContext``
/// Calls the provided `self.body` closure with the ``ByteBuffer`` invocation event, the ``LambdaResponseStreamWriter``, and the ``LambdaContext``
/// - Parameters:
/// - event: The invocation's input data.
/// - responseWriter: A ``LambdaResponseStreamWriter`` to write the invocation's response to.
/// If no response or error is written to `responseWriter` an error will be reported to the invoker.
/// - context: The ``NewLambdaContext`` containing the invocation's metadata.
/// - context: The ``LambdaContext`` containing the invocation's metadata.
package func handle(
_ request: ByteBuffer,
responseWriter: some LambdaResponseStreamWriter,
context: NewLambdaContext
context: LambdaContext
) async throws {
try await self.body(request, responseWriter, context)
}
}

/// A ``NewLambdaHandler`` conforming handler object that can be constructed with a closure.
/// A ``LambdaHandler`` conforming handler object that can be constructed with a closure.
/// Allows for a handler to be defined in a clean manner, leveraging Swift's trailing closure syntax.
package struct ClosureHandler<Event: Decodable, Output>: NewLambdaHandler {
let body: (Event, NewLambdaContext) async throws -> Output
package struct ClosureHandler<Event: Decodable, Output>: LambdaHandler {
let body: (Event, LambdaContext) async throws -> Output

/// Initialize with a closure handler over generic `Input` and `Output` types.
/// - Parameter body: The handler function written as a closure.
package init(body: @escaping (Event, NewLambdaContext) async throws -> Output) where Output: Encodable {
package init(body: @escaping (Event, LambdaContext) async throws -> Output) where Output: Encodable {
self.body = body
}

/// Initialize with a closure handler over a generic `Input` type, and a `Void` `Output`.
/// - Parameter body: The handler function written as a closure.
package init(body: @escaping (Event, NewLambdaContext) async throws -> Void) where Output == Void {
package init(body: @escaping (Event, LambdaContext) async throws -> Void) where Output == Void {
self.body = body
}

/// Calls the provided `self.body` closure with the generic ``Event`` object representing the incoming event, and the ``NewLambdaContext``
/// Calls the provided `self.body` closure with the generic ``Event`` object representing the incoming event, and the ``LambdaContext``
/// - Parameters:
/// - event: The generic ``Event`` object representing the invocation's input data.
/// - context: The ``NewLambdaContext`` containing the invocation's metadata.
package func handle(_ event: Event, context: NewLambdaContext) async throws -> Output {
/// - context: The ``LambdaContext`` containing the invocation's metadata.
package func handle(_ event: Event, context: LambdaContext) async throws -> Output {
try await self.body(event, context)
}
}

extension NewLambdaRuntime {
extension LambdaRuntime {
/// Initialize an instance with a ``StreamingLambdaHandler`` in the form of a closure.
/// - Parameter body: The handler in the form of a closure.
package convenience init(
body: @Sendable @escaping (ByteBuffer, LambdaResponseStreamWriter, NewLambdaContext) async throws -> Void
body: @Sendable @escaping (ByteBuffer, LambdaResponseStreamWriter, LambdaContext) async throws -> Void
) where Handler == StreamingClosureHandler {
self.init(handler: StreamingClosureHandler(body: body))
}

/// Initialize an instance with a ``NewLambdaHandler`` defined in the form of a closure **with a non-`Void` return type**, an encoder, and a decoder.
/// Initialize an instance with a ``LambdaHandler`` defined in the form of a closure **with a non-`Void` return type**, an encoder, and a decoder.
/// - Parameter body: The handler in the form of a closure.
/// - Parameter encoder: The encoder object that will be used to encode the generic ``Output`` into a ``ByteBuffer``.
/// - Parameter decoder: The decoder object that will be used to decode the incoming ``ByteBuffer`` event into the generic ``Event`` type.
Expand All @@ -193,7 +193,7 @@ extension NewLambdaRuntime {
>(
encoder: Encoder,
decoder: Decoder,
body: @escaping (Event, NewLambdaContext) async throws -> Output
body: @escaping (Event, LambdaContext) async throws -> Output
)
where
Handler == LambdaCodableAdapter<
Expand All @@ -213,13 +213,13 @@ extension NewLambdaRuntime {
self.init(handler: handler)
}

/// Initialize an instance with a ``NewLambdaHandler`` defined in the form of a closure **with a `Void` return type**, an encoder, and a decoder.
/// Initialize an instance with a ``LambdaHandler`` defined in the form of a closure **with a `Void` return type**, an encoder, and a decoder.
/// - Parameter body: The handler in the form of a closure.
/// - Parameter encoder: The encoder object that will be used to encode the generic ``Output`` into a ``ByteBuffer``.
/// - Parameter decoder: The decoder object that will be used to decode the incoming ``ByteBuffer`` event into the generic ``Event`` type.
package convenience init<Event: Decodable, Decoder: LambdaEventDecoder>(
decoder: Decoder,
body: @escaping (Event, NewLambdaContext) async throws -> Void
body: @escaping (Event, LambdaContext) async throws -> Void
)
where
Handler == LambdaCodableAdapter<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import NIOConcurrencyHelpers
// We need `@unchecked` Sendable here, as `NIOLockedValueBox` does not understand `sending` today.
// We don't want to use `NIOLockedValueBox` here anyway. We would love to use Mutex here, but this
// sadly crashes the compiler today.
package final class NewLambdaRuntime<Handler>: @unchecked Sendable where Handler: StreamingLambdaHandler {
package final class LambdaRuntime<Handler>: @unchecked Sendable where Handler: StreamingLambdaHandler {
// TODO: We want to change this to Mutex as soon as this doesn't crash the Swift compiler on Linux anymore
let handlerMutex: NIOLockedValueBox<Optional<Handler>>
let logger: Logger
Expand All @@ -38,12 +38,12 @@ package final class NewLambdaRuntime<Handler>: @unchecked Sendable where Handler

package func run() async throws {
guard let runtimeEndpoint = Lambda.env("AWS_LAMBDA_RUNTIME_API") else {
throw NewLambdaRuntimeError(code: .missingLambdaRuntimeAPIEnvironmentVariable)
throw LambdaRuntimeError(code: .missingLambdaRuntimeAPIEnvironmentVariable)
}

let ipAndPort = runtimeEndpoint.split(separator: ":", maxSplits: 1)
let ip = String(ipAndPort[0])
guard let port = Int(ipAndPort[1]) else { throw NewLambdaRuntimeError(code: .invalidPort) }
guard let port = Int(ipAndPort[1]) else { throw LambdaRuntimeError(code: .invalidPort) }

let handler = self.handlerMutex.withLockedValue { handler in
let result = handler
Expand All @@ -52,10 +52,10 @@ package final class NewLambdaRuntime<Handler>: @unchecked Sendable where Handler
}

guard let handler else {
throw NewLambdaRuntimeError(code: .runtimeCanOnlyBeStartedOnce)
throw LambdaRuntimeError(code: .runtimeCanOnlyBeStartedOnce)
}

try await NewLambdaRuntimeClient.withRuntimeClient(
try await LambdaRuntimeClient.withRuntimeClient(
configuration: .init(ip: ip, port: port),
eventLoop: self.eventLoop,
logger: self.logger
Expand Down
Loading
Loading