Skip to content
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

API Refactoring #273

Merged
merged 6 commits into from
Nov 9, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
refactor API towards 1.0
motivation: define stable API in preperation 1.0 release

changes:
* require swift 5.7, remove redundant backwards compatibility code
* make LambdaHandler, EventLoopLambdaHandler, and ByteBufferLambdaHandler disjointed protocols to reduce API surface area
* create coding wrappers for LambdaHandler and EventLoopLambdaHandler to provide coding bridge
* reuse output ByteBuffer to reduce allocationsi
* add no-op initializer for simple landa use cases
* update callsites and tests
  • Loading branch information
tomerd committed Oct 8, 2022
commit 457e0c389d5704bfedcc35b9fd0c567b880db8f9
55 changes: 0 additions & 55 deletions Package@swift-5.4.swift

This file was deleted.

55 changes: 0 additions & 55 deletions Package@swift-5.5.swift

This file was deleted.

55 changes: 43 additions & 12 deletions Sources/AWSLambdaRuntime/Lambda+Codable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,45 @@ import class Foundation.JSONEncoder
import NIOCore
import NIOFoundationCompat

// MARK: - Codable support
// MARK: - LambdaHandler Codable support

/// Implementation of a`ByteBuffer` to `Event` decoding.
tomerd marked this conversation as resolved.
Show resolved Hide resolved
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
extension LambdaHandler where Event: Decodable {
@inlinable
public func decode(buffer: ByteBuffer) throws -> Event {
try self.decoder.decode(Event.self, from: buffer)
}
}

/// Implementation of `Output` to `ByteBuffer` encoding.
tomerd marked this conversation as resolved.
Show resolved Hide resolved
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
extension LambdaHandler where Output: Encodable {
@inlinable
public func encode(value: Output, into buffer: inout ByteBuffer) throws {
try self.encoder.encode(value, into: &buffer)
}
}

/// 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.
tomerd marked this conversation as resolved.
Show resolved Hide resolved
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
extension LambdaHandler where Event: Decodable {
public var decoder: LambdaCodableDecoder {
Lambda.defaultJSONDecoder
}
}

/// 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.
tomerd marked this conversation as resolved.
Show resolved Hide resolved
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
extension LambdaHandler where Output: Encodable {
public var encoder: LambdaCodableEncoder {
Lambda.defaultJSONEncoder
}
}

// MARK: - EventLoopLambdaHandler Codable support

/// Implementation of a`ByteBuffer` to `Event` decoding.
tomerd marked this conversation as resolved.
Show resolved Hide resolved
extension EventLoopLambdaHandler where Event: Decodable {
Expand All @@ -32,8 +70,8 @@ extension EventLoopLambdaHandler where Event: Decodable {
/// Implementation of `Output` to `ByteBuffer` encoding.
tomerd marked this conversation as resolved.
Show resolved Hide resolved
extension EventLoopLambdaHandler where Output: Encodable {
@inlinable
public func encode(allocator: ByteBufferAllocator, value: Output) throws -> ByteBuffer? {
try self.encoder.encode(value, using: allocator)
public func encode(value: Output, into buffer: inout ByteBuffer) throws {
try self.encoder.encode(value, into: &buffer)
}
}

Expand All @@ -58,7 +96,7 @@ public protocol LambdaCodableDecoder {
}

public protocol LambdaCodableEncoder {
func encode<T: Encodable>(_ value: T, using allocator: ByteBufferAllocator) throws -> ByteBuffer
func encode<T: Encodable>(_ value: T, into buffer: inout ByteBuffer) throws
}

extension Lambda {
Expand All @@ -68,11 +106,4 @@ extension Lambda {

extension JSONDecoder: LambdaCodableDecoder {}

extension JSONEncoder: LambdaCodableEncoder {
public func encode<T>(_ value: T, using allocator: ByteBufferAllocator) throws -> ByteBuffer where T: Encodable {
// nio will resize the buffer if necessary
var buffer = allocator.buffer(capacity: 1024)
try self.encode(value, into: &buffer)
return buffer
}
}
extension JSONEncoder: LambdaCodableEncoder {}
41 changes: 31 additions & 10 deletions Sources/AWSLambdaRuntimeCore/Lambda+String.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,46 @@
//===----------------------------------------------------------------------===//
import NIOCore

extension EventLoopLambdaHandler where Event == String {
// MARK: - LambdaHandler String support

@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
tomerd marked this conversation as resolved.
Show resolved Hide resolved
extension LambdaHandler where Event == String {
/// Implementation of a `ByteBuffer` to `String` decoding.
@inlinable
public func decode(buffer: ByteBuffer) throws -> String {
var buffer = buffer
guard let string = buffer.readString(length: buffer.readableBytes) else {
fatalError("buffer.readString(length: buffer.readableBytes) failed")
guard let value = buffer.getString(at: buffer.readerIndex, length: buffer.readableBytes) else {
throw CodecError.invalidString
}
return string
return value
}
}

extension EventLoopLambdaHandler where Output == String {
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
extension LambdaHandler where Output == String {
/// Implementation of `String` to `ByteBuffer` encoding.
@inlinable
public func encode(allocator: ByteBufferAllocator, value: String) throws -> ByteBuffer? {
// FIXME: reusable buffer
var buffer = allocator.buffer(capacity: value.utf8.count)
public func encode(value: String, into buffer: inout ByteBuffer) throws {
buffer.writeString(value)
}
}

// MARK: - EventLoopLambdaHandler String support

extension EventLoopLambdaHandler where Event == String {
/// Implementation of `String` to `ByteBuffer` encoding.
@inlinable
public func decode(buffer: ByteBuffer) throws -> String {
guard let value = buffer.getString(at: buffer.readerIndex, length: buffer.readableBytes) else {
throw CodecError.invalidString
}
return value
}
}

extension EventLoopLambdaHandler where Output == String {
/// Implementation of a `ByteBuffer` to `String` decoding.
@inlinable
public func encode(value: String, into buffer: inout ByteBuffer) throws {
buffer.writeString(value)
return buffer
}
}
21 changes: 18 additions & 3 deletions Sources/AWSLambdaRuntimeCore/Lambda.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,25 @@ public enum Lambda {
/// - handlerType: The Handler to create and invoke.
///
/// - note: This is a blocking operation that will run forever, as its lifecycle is managed by the AWS Lambda Runtime Engine.
internal static func run<Handler: ByteBufferLambdaHandler>(

@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
internal static func run<Handler: LambdaHandler>(
configuration: LambdaConfiguration = .init(),
handlerType: Handler.Type
) -> Result<Int, Error> {
Self.run(configuration: configuration, handlerType: CodableLambdaHandler<Handler>.self)
}

internal static func run<Handler: EventLoopLambdaHandler>(
configuration: LambdaConfiguration = .init(),
handlerType: Handler.Type
) -> Result<Int, Error> {
Self.run(configuration: configuration, handlerType: CodableEventLoopLambdaHandler<Handler>.self)
}

internal static func run(
configuration: LambdaConfiguration = .init(),
handlerType: (some ByteBufferLambdaHandler).Type
) -> Result<Int, Error> {
let _run = { (configuration: LambdaConfiguration) -> Result<Int, Error> in
Backtrace.install()
Expand All @@ -44,7 +60,7 @@ public enum Lambda {

var result: Result<Int, Error>!
MultiThreadedEventLoopGroup.withCurrentThreadAsEventLoop { eventLoop in
let runtime = LambdaRuntime<Handler>(eventLoop: eventLoop, logger: logger, configuration: configuration)
let runtime = LambdaRuntime(handlerType, eventLoop: eventLoop, logger: logger, configuration: configuration)
#if DEBUG
let signalSource = trap(signal: configuration.lifecycle.stopSignal) { signal in
logger.info("intercepted signal: \(signal)")
Expand All @@ -66,7 +82,6 @@ public enum Lambda {
result = lifecycleResult
}
}

logger.info("shutdown completed")
return result
}
Expand Down
12 changes: 3 additions & 9 deletions Sources/AWSLambdaRuntimeCore/LambdaContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,17 @@
//
//===----------------------------------------------------------------------===//

#if compiler(>=5.6)
@preconcurrency import Dispatch
@preconcurrency import Logging
@preconcurrency import NIOCore
#else
import Dispatch
import Logging
import NIOCore
#endif

// MARK: - InitializationContext

/// Lambda runtime initialization context.
/// The Lambda runtime generates and passes the `LambdaInitializationContext` to the Handlers
/// ``ByteBufferLambdaHandler/makeHandler(context:)`` or ``LambdaHandler/init(context:)``
/// as an argument.
public struct LambdaInitializationContext: _AWSLambdaSendable {
public struct LambdaInitializationContext: Sendable {
/// `Logger` to log with.
///
/// - note: The `LogLevel` can be configured using the `LOG_LEVEL` environment variable.
Expand Down Expand Up @@ -71,8 +65,8 @@ public struct LambdaInitializationContext: _AWSLambdaSendable {

/// Lambda runtime context.
/// The Lambda runtime generates and passes the `LambdaContext` to the Lambda handler as an argument.
public struct LambdaContext: CustomDebugStringConvertible, _AWSLambdaSendable {
final class _Storage: _AWSLambdaSendable {
public struct LambdaContext: CustomDebugStringConvertible, Sendable {
final class _Storage: Sendable {
fabianfett marked this conversation as resolved.
Show resolved Hide resolved
let requestID: String
let traceID: String
let invokedFunctionARN: String
Expand Down
Loading