Skip to content

[RFC] Drop event label from handle methods in LambdaHandlers #225

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 22, 2021
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
6 changes: 3 additions & 3 deletions Examples/LambdaFunctions/Sources/Benchmark/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ import NIO
Lambda.run { $0.eventLoop.makeSucceededFuture(BenchmarkHandler()) }

struct BenchmarkHandler: EventLoopLambdaHandler {
typealias In = String
typealias Out = String
typealias Event = String
typealias Output = String

func handle(event: String, context: Lambda.Context) -> EventLoopFuture<String> {
func handle(_ event: String, context: Lambda.Context) -> EventLoopFuture<String> {
context.eventLoop.makeSucceededFuture("hello, world!")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ import Logging

@main
struct CurrencyExchangeHandler: LambdaHandler {
typealias In = Request
typealias Out = [Exchange]
typealias Event = Request
typealias Output = [Exchange]

let calculator: ExchangeRatesCalculator

Expand All @@ -35,7 +35,7 @@ struct CurrencyExchangeHandler: LambdaHandler {
self.calculator = ExchangeRatesCalculator()
}

func handle(event: Request, context: Lambda.Context) async throws -> [Exchange] {
func handle(_ event: Request, context: Lambda.Context) async throws -> [Exchange] {
try await withCheckedThrowingContinuation { continuation in
self.calculator.run(logger: context.logger) { result in
switch result {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ import AWSLambdaRuntime

@main
struct ErrorsHappenHandler: LambdaHandler {
typealias In = Request
typealias Out = Response
typealias Event = Request
typealias Output = Response

init(context: Lambda.InitializationContext) async throws {}

func handle(event request: Request, context: Lambda.Context) async throws -> Response {
func handle(_ request: Request, context: Lambda.Context) async throws -> Response {
// switch over the error type "requested" by the request, and trigger such error accordingly
switch request.error {
// no error here!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ import AWSLambdaRuntime
// introductory example, the obligatory "hello, world!"
@main
struct HelloWorldHandler: LambdaHandler {
typealias In = String
typealias Out = String
typealias Event = String
typealias Output = String

init(context: Lambda.InitializationContext) async throws {
// setup your resources that you want to reuse here.
}

func handle(event: String, context: Lambda.Context) async throws -> String {
func handle(_ event: String, context: Lambda.Context) async throws -> String {
"hello, world"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ import Shared
// a local server simulator which will allow local debugging
@main
struct MyLambdaHandler: LambdaHandler {
typealias In = Request
typealias Out = Response
typealias Event = Request
typealias Output = Response

init(context: Lambda.InitializationContext) async throws {
// setup your resources that you want to reuse for every invocation here.
}

func handle(event request: Request, context: Lambda.Context) async throws -> Response {
func handle(_ request: Request, context: Lambda.Context) async throws -> Response {
// TODO: something useful
Response(message: "Hello, \(request.name)!")
}
Expand Down
22 changes: 11 additions & 11 deletions Sources/AWSLambdaRuntime/Lambda+Codable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,33 @@ import NIOFoundationCompat

// MARK: - Codable support

/// Implementation of a`ByteBuffer` to `In` decoding
extension EventLoopLambdaHandler where In: Decodable {
/// Implementation of a`ByteBuffer` to `Event` decoding
extension EventLoopLambdaHandler where Event: Decodable {
@inlinable
public func decode(buffer: ByteBuffer) throws -> In {
try self.decoder.decode(In.self, from: buffer)
public func decode(buffer: ByteBuffer) throws -> Event {
try self.decoder.decode(Event.self, from: buffer)
}
}

/// Implementation of `Out` to `ByteBuffer` encoding
extension EventLoopLambdaHandler where Out: Encodable {
/// Implementation of `Output` to `ByteBuffer` encoding
extension EventLoopLambdaHandler where Output: Encodable {
@inlinable
public func encode(allocator: ByteBufferAllocator, value: Out) throws -> ByteBuffer? {
public func encode(allocator: ByteBufferAllocator, value: Output) throws -> ByteBuffer? {
try self.encoder.encode(value, using: allocator)
}
}

/// Default `ByteBuffer` to `In` decoder using Foundation's JSONDecoder
/// Default `ByteBuffer` to `Event` decoder using Foundation's JSONDecoder
/// Advanced users that want to inject their own codec can do it by overriding these functions.
extension EventLoopLambdaHandler where In: Decodable {
extension EventLoopLambdaHandler where Event: Decodable {
public var decoder: LambdaCodableDecoder {
Lambda.defaultJSONDecoder
}
}

/// Default `Out` to `ByteBuffer` encoder using Foundation's JSONEncoder
/// Default `Output` to `ByteBuffer` encoder using Foundation's JSONEncoder
/// Advanced users that want to inject their own codec can do it by overriding these functions.
extension EventLoopLambdaHandler where Out: Encodable {
extension EventLoopLambdaHandler where Output: Encodable {
public var encoder: LambdaCodableEncoder {
Lambda.defaultJSONEncoder
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/AWSLambdaRuntimeCore/Lambda+String.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
import NIOCore

extension EventLoopLambdaHandler where In == String {
extension EventLoopLambdaHandler where Event == String {
/// Implementation of a `ByteBuffer` to `String` decoding
@inlinable
public func decode(buffer: ByteBuffer) throws -> String {
Expand All @@ -25,7 +25,7 @@ extension EventLoopLambdaHandler where In == String {
}
}

extension EventLoopLambdaHandler where Out == String {
extension EventLoopLambdaHandler where Output == String {
/// Implementation of `String` to `ByteBuffer` encoding
@inlinable
public func encode(allocator: ByteBufferAllocator, value: String) throws -> ByteBuffer? {
Expand Down
52 changes: 26 additions & 26 deletions Sources/AWSLambdaRuntimeCore/LambdaHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import NIOCore
// MARK: - LambdaHandler

#if compiler(>=5.5)
/// Strongly typed, processing protocol for a Lambda that takes a user defined `In` and returns a user defined `Out` async.
/// Strongly typed, processing protocol for a Lambda that takes a user defined `Event` and returns a user defined `Output` async.
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
public protocol LambdaHandler: EventLoopLambdaHandler {
/// The Lambda initialization method
Expand All @@ -34,19 +34,19 @@ public protocol LambdaHandler: EventLoopLambdaHandler {
/// Concrete Lambda handlers implement this method to provide the Lambda functionality.
///
/// - parameters:
/// - event: Event of type `In` representing the event or request.
/// - event: Event of type `Event` representing the event or request.
/// - context: Runtime `Context`.
///
/// - Returns: A Lambda result ot type `Out`.
func handle(event: In, context: Lambda.Context) async throws -> Out
/// - Returns: A Lambda result ot type `Output`.
func handle(_ event: Event, context: Lambda.Context) async throws -> Output
}

@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
extension LambdaHandler {
public func handle(event: In, context: Lambda.Context) -> EventLoopFuture<Out> {
let promise = context.eventLoop.makePromise(of: Out.self)
public func handle(_ event: Event, context: Lambda.Context) -> EventLoopFuture<Output> {
let promise = context.eventLoop.makePromise(of: Output.self)
promise.completeWithTask {
try await self.handle(event: event, context: context)
try await self.handle(event, context: context)
}
return promise.futureResult
}
Expand All @@ -62,59 +62,59 @@ extension LambdaHandler {

// MARK: - EventLoopLambdaHandler

/// Strongly typed, `EventLoopFuture` based processing protocol for a Lambda that takes a user defined `In` and returns a user defined `Out` asynchronously.
/// `EventLoopLambdaHandler` extends `ByteBufferLambdaHandler`, performing `ByteBuffer` -> `In` decoding and `Out` -> `ByteBuffer` encoding.
/// Strongly typed, `EventLoopFuture` based processing protocol for a Lambda that takes a user defined `Event` and returns a user defined `Output` asynchronously.
/// `EventLoopLambdaHandler` extends `ByteBufferLambdaHandler`, performing `ByteBuffer` -> `Event` decoding and `Output` -> `ByteBuffer` encoding.
///
/// - note: To implement a Lambda, implement either `LambdaHandler` or the `EventLoopLambdaHandler` protocol.
/// The `LambdaHandler` will offload the Lambda execution to a `DispatchQueue` making processing safer but slower
/// The `EventLoopLambdaHandler` will execute the Lambda on the same `EventLoop` as the core runtime engine, making the processing faster but requires
/// more care from the implementation to never block the `EventLoop`.
public protocol EventLoopLambdaHandler: ByteBufferLambdaHandler {
associatedtype In
associatedtype Out
associatedtype Event
associatedtype Output

/// The Lambda handling method
/// Concrete Lambda handlers implement this method to provide the Lambda functionality.
///
/// - parameters:
/// - context: Runtime `Context`.
/// - event: Event of type `In` representing the event or request.
/// - event: Event of type `Event` representing the event or request.
///
/// - Returns: An `EventLoopFuture` to report the result of the Lambda back to the runtime engine.
/// The `EventLoopFuture` should be completed with either a response of type `Out` or an `Error`
func handle(event: In, context: Lambda.Context) -> EventLoopFuture<Out>
/// The `EventLoopFuture` should be completed with either a response of type `Output` or an `Error`
func handle(_ event: Event, context: Lambda.Context) -> EventLoopFuture<Output>

/// Encode a response of type `Out` to `ByteBuffer`
/// Encode a response of type `Output` to `ByteBuffer`
/// Concrete Lambda handlers implement this method to provide coding functionality.
/// - parameters:
/// - allocator: A `ByteBufferAllocator` to help allocate the `ByteBuffer`.
/// - value: Response of type `Out`.
/// - value: Response of type `Output`.
///
/// - Returns: A `ByteBuffer` with the encoded version of the `value`.
func encode(allocator: ByteBufferAllocator, value: Out) throws -> ByteBuffer?
func encode(allocator: ByteBufferAllocator, value: Output) throws -> ByteBuffer?

/// Decode a`ByteBuffer` to a request or event of type `In`
/// Decode a`ByteBuffer` to a request or event of type `Event`
/// Concrete Lambda handlers implement this method to provide coding functionality.
///
/// - parameters:
/// - buffer: The `ByteBuffer` to decode.
///
/// - Returns: A request or event of type `In`.
func decode(buffer: ByteBuffer) throws -> In
/// - Returns: A request or event of type `Event`.
func decode(buffer: ByteBuffer) throws -> Event
}

extension EventLoopLambdaHandler {
/// Driver for `ByteBuffer` -> `In` decoding and `Out` -> `ByteBuffer` encoding
/// Driver for `ByteBuffer` -> `Event` decoding and `Output` -> `ByteBuffer` encoding
@inlinable
public func handle(event: ByteBuffer, context: Lambda.Context) -> EventLoopFuture<ByteBuffer?> {
let input: In
public func handle(_ event: ByteBuffer, context: Lambda.Context) -> EventLoopFuture<ByteBuffer?> {
let input: Event
do {
input = try self.decode(buffer: event)
} catch {
return context.eventLoop.makeFailedFuture(CodecError.requestDecoding(error))
}

return self.handle(event: input, context: context).flatMapThrowing { output in
return self.handle(input, context: context).flatMapThrowing { output in
do {
return try self.encode(allocator: context.allocator, value: output)
} catch {
Expand All @@ -125,7 +125,7 @@ extension EventLoopLambdaHandler {
}

/// Implementation of `ByteBuffer` to `Void` decoding
extension EventLoopLambdaHandler where Out == Void {
extension EventLoopLambdaHandler where Output == Void {
@inlinable
public func encode(allocator: ByteBufferAllocator, value: Void) throws -> ByteBuffer? {
nil
Expand All @@ -148,7 +148,7 @@ public protocol ByteBufferLambdaHandler {
///
/// - Returns: An `EventLoopFuture` to report the result of the Lambda back to the runtime engine.
/// The `EventLoopFuture` should be completed with either a response encoded as `ByteBuffer` or an `Error`
func handle(event: ByteBuffer, context: Lambda.Context) -> EventLoopFuture<ByteBuffer?>
func handle(_ event: ByteBuffer, context: Lambda.Context) -> EventLoopFuture<ByteBuffer?>

/// Clean up the Lambda resources asynchronously.
/// Concrete Lambda handlers implement this method to shutdown resources like `HTTPClient`s and database connections.
Expand Down
4 changes: 2 additions & 2 deletions Sources/AWSLambdaRuntimeCore/LambdaRunner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,15 @@ extension Lambda {
self.isGettingNextInvocation = true
return self.runtimeClient.getNextInvocation(logger: logger).peekError { error in
logger.error("could not fetch work from lambda runtime engine: \(error)")
}.flatMap { invocation, event in
}.flatMap { invocation, bytes in
// 2. send invocation to handler
self.isGettingNextInvocation = false
let context = Context(logger: logger,
eventLoop: self.eventLoop,
allocator: self.allocator,
invocation: invocation)
logger.debug("sending invocation to lambda handler \(handler)")
return handler.handle(event: event, context: context)
return handler.handle(bytes, context: context)
// Hopping back to "our" EventLoop is important in case the handler returns a future that
// originiated from a foreign EventLoop/EventLoopGroup.
// This can happen if the handler uses a library (lets say a DB client) that manages its own threads/loops
Expand Down
6 changes: 3 additions & 3 deletions Sources/AWSLambdaTesting/Lambda+Testing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ extension Lambda {

public static func test<Handler: LambdaHandler>(
_ handlerType: Handler.Type,
with event: Handler.In,
with event: Handler.Event,
using config: TestConfig = .init()
) throws -> Handler.Out {
) throws -> Handler.Output {
let logger = Logger(label: "test")
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
defer {
Expand Down Expand Up @@ -97,7 +97,7 @@ extension Lambda {
let handler = try promise.futureResult.wait()

return try eventLoop.flatSubmit {
handler.handle(event: event, context: context)
handler.handle(event, context: context)
}.wait()
}
}
Expand Down
6 changes: 3 additions & 3 deletions Sources/CodableSample/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ struct Response: Codable {
// in this example we are receiving and responding with codables. Request and Response above are examples of how to use
// codables to model your reqeuest and response objects
struct Handler: EventLoopLambdaHandler {
typealias In = Request
typealias Out = Response
typealias Event = Request
typealias Output = Response

func handle(event: Request, context: Lambda.Context) -> EventLoopFuture<Response> {
func handle(_ event: Request, context: Lambda.Context) -> EventLoopFuture<Response> {
// as an example, respond with the input event's reversed body
context.eventLoop.makeSucceededFuture(Response(body: String(event.body.reversed())))
}
Expand Down
6 changes: 3 additions & 3 deletions Sources/StringSample/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ import NIOCore

// in this example we are receiving and responding with strings
struct Handler: EventLoopLambdaHandler {
typealias In = String
typealias Out = String
typealias Event = String
typealias Output = String

func handle(event: String, context: Lambda.Context) -> EventLoopFuture<String> {
func handle(_ event: String, context: Lambda.Context) -> EventLoopFuture<String> {
// as an example, respond with the event's reversed body
context.eventLoop.makeSucceededFuture(String(event.reversed()))
}
Expand Down
Loading