Skip to content

Commit 3eda467

Browse files
authored
Merge branch 'main' into ff-use-mutex
2 parents b299131 + 4295e51 commit 3eda467

File tree

6 files changed

+59
-45
lines changed

6 files changed

+59
-45
lines changed

Package.swift

+1-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ let package = Package(
3333
.byName(name: "AWSLambdaRuntimeCore"),
3434
.product(name: "NIOCore", package: "swift-nio"),
3535
.product(name: "NIOFoundationCompat", package: "swift-nio"),
36-
],
37-
swiftSettings: [.swiftLanguageMode(.v5)]
36+
]
3837
),
3938
.target(
4039
name: "AWSLambdaRuntimeCore",

Sources/AWSLambdaRuntime/Lambda+Codable.swift

+8-7
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,14 @@ extension LambdaCodableAdapter {
6767

6868
extension LambdaRuntime {
6969
/// Initialize an instance with a `LambdaHandler` defined in the form of a closure **with a non-`Void` return type**.
70-
/// - Parameter body: The handler in the form of a closure.
71-
/// - Parameter encoder: The encoder object that will be used to encode the generic `Output` into a `ByteBuffer`. `JSONEncoder()` used as default.
72-
/// - Parameter decoder: The decoder object that will be used to decode the incoming `ByteBuffer` event into the generic `Event` type. `JSONDecoder()` used as default.
70+
/// - Parameters:
71+
/// - decoder: The decoder object that will be used to decode the incoming `ByteBuffer` event into the generic `Event` type. `JSONDecoder()` used as default.
72+
/// - encoder: The encoder object that will be used to encode the generic `Output` into a `ByteBuffer`. `JSONEncoder()` used as default.
73+
/// - body: The handler in the form of a closure.
7374
public convenience init<Event: Decodable, Output>(
74-
body: @escaping (Event, LambdaContext) async throws -> Output,
75+
decoder: JSONDecoder = JSONDecoder(),
7576
encoder: JSONEncoder = JSONEncoder(),
76-
decoder: JSONDecoder = JSONDecoder()
77+
body: sending @escaping (Event, LambdaContext) async throws -> Output
7778
)
7879
where
7980
Handler == LambdaCodableAdapter<
@@ -97,8 +98,8 @@ extension LambdaRuntime {
9798
/// - Parameter body: The handler in the form of a closure.
9899
/// - Parameter decoder: The decoder object that will be used to decode the incoming `ByteBuffer` event into the generic `Event` type. `JSONDecoder()` used as default.
99100
public convenience init<Event: Decodable>(
100-
body: @escaping (Event, LambdaContext) async throws -> Void,
101-
decoder: JSONDecoder = JSONDecoder()
101+
decoder: JSONDecoder = JSONDecoder(),
102+
body: sending @escaping (Event, LambdaContext) async throws -> Void
102103
)
103104
where
104105
Handler == LambdaCodableAdapter<

Sources/AWSLambdaRuntimeCore/Lambda.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public enum Lambda {
6060
}
6161

6262
/// The default EventLoop the Lambda is scheduled on.
63-
public static var defaultEventLoop: any EventLoop = NIOSingletons.posixEventLoopGroup.next()
63+
public static let defaultEventLoop: any EventLoop = NIOSingletons.posixEventLoopGroup.next()
6464
}
6565

6666
// MARK: - Public API

Sources/AWSLambdaRuntimeCore/LambdaHandlers.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ extension LambdaRuntime {
194194
>(
195195
encoder: Encoder,
196196
decoder: Decoder,
197-
body: @escaping (Event, LambdaContext) async throws -> Output
197+
body: sending @escaping (Event, LambdaContext) async throws -> Output
198198
)
199199
where
200200
Handler == LambdaCodableAdapter<
@@ -220,7 +220,7 @@ extension LambdaRuntime {
220220
/// - body: The handler in the form of a closure.
221221
public convenience init<Event: Decodable, Decoder: LambdaEventDecoder>(
222222
decoder: Decoder,
223-
body: @escaping (Event, LambdaContext) async throws -> Void
223+
body: sending @escaping (Event, LambdaContext) async throws -> Void
224224
)
225225
where
226226
Handler == LambdaCodableAdapter<

Sources/AWSLambdaRuntimeCore/LambdaRequestID.swift

+4-3
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,16 @@ struct LambdaRequestID {
8888
}
8989

9090
/// thread safe secure random number generator.
91-
private static var generator = SystemRandomNumberGenerator()
9291
private static func generateRandom() -> Self {
92+
var generator = SystemRandomNumberGenerator()
93+
9394
var _uuid: uuid_t = LambdaRequestID.null
9495
// https://tools.ietf.org/html/rfc4122#page-14
9596
// o Set all the other bits to randomly (or pseudo-randomly) chosen
9697
// values.
9798
withUnsafeMutableBytes(of: &_uuid) { ptr in
98-
ptr.storeBytes(of: Self.generator.next(), toByteOffset: 0, as: UInt64.self)
99-
ptr.storeBytes(of: Self.generator.next(), toByteOffset: 8, as: UInt64.self)
99+
ptr.storeBytes(of: generator.next(), toByteOffset: 0, as: UInt64.self)
100+
ptr.storeBytes(of: generator.next(), toByteOffset: 8, as: UInt64.self)
100101
}
101102

102103
// o Set the four most significant bits (bits 12 through 15) of the

Tests/AWSLambdaRuntimeCoreTests/MockLambdaServer.swift

+43-30
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ func withMockServer<Result>(
2727
_ body: (_ port: Int) async throws -> Result
2828
) async throws -> Result {
2929
let eventLoopGroup = NIOSingletons.posixEventLoopGroup
30-
let server = MockLambdaServer(behavior: behaviour, port: port, keepAlive: keepAlive)
31-
let port = try await server.start().get()
30+
let server = MockLambdaServer(behavior: behaviour, port: port, keepAlive: keepAlive, eventLoopGroup: eventLoopGroup)
31+
let port = try await server.start()
3232

3333
let result: Swift.Result<Result, any Error>
3434
do {
@@ -37,13 +37,13 @@ func withMockServer<Result>(
3737
result = .failure(error)
3838
}
3939

40-
try? await server.stop().get()
40+
try? await server.stop()
4141
return try result.get()
4242
}
4343

44-
final class MockLambdaServer {
44+
final class MockLambdaServer<Behavior: LambdaServerBehavior> {
4545
private let logger = Logger(label: "MockLambdaServer")
46-
private let behavior: LambdaServerBehavior
46+
private let behavior: Behavior
4747
private let host: String
4848
private let port: Int
4949
private let keepAlive: Bool
@@ -52,7 +52,13 @@ final class MockLambdaServer {
5252
private var channel: Channel?
5353
private var shutdown = false
5454

55-
init(behavior: LambdaServerBehavior, host: String = "127.0.0.1", port: Int = 7000, keepAlive: Bool = true) {
55+
init(
56+
behavior: Behavior,
57+
host: String = "127.0.0.1",
58+
port: Int = 7000,
59+
keepAlive: Bool = true,
60+
eventLoopGroup: MultiThreadedEventLoopGroup
61+
) {
5662
self.group = NIOSingletons.posixEventLoopGroup
5763
self.behavior = behavior
5864
self.host = host
@@ -64,39 +70,41 @@ final class MockLambdaServer {
6470
assert(shutdown)
6571
}
6672

67-
func start() -> EventLoopFuture<Int> {
68-
let bootstrap = ServerBootstrap(group: group)
73+
fileprivate func start() async throws -> Int {
74+
let logger = self.logger
75+
let keepAlive = self.keepAlive
76+
let behavior = self.behavior
77+
78+
let channel = try await ServerBootstrap(group: group)
6979
.serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
7080
.childChannelInitializer { channel in
7181
do {
7282
try channel.pipeline.syncOperations.configureHTTPServerPipeline(withErrorHandling: true)
7383
try channel.pipeline.syncOperations.addHandler(
74-
HTTPHandler(logger: self.logger, keepAlive: self.keepAlive, behavior: self.behavior)
84+
HTTPHandler(logger: logger, keepAlive: keepAlive, behavior: behavior)
7585
)
7686
return channel.eventLoop.makeSucceededVoidFuture()
7787
} catch {
7888
return channel.eventLoop.makeFailedFuture(error)
7989
}
8090
}
81-
return bootstrap.bind(host: self.host, port: self.port).flatMap { channel in
82-
self.channel = channel
83-
guard let localAddress = channel.localAddress else {
84-
return channel.eventLoop.makeFailedFuture(ServerError.cantBind)
85-
}
86-
self.logger.info("\(self) started and listening on \(localAddress)")
87-
return channel.eventLoop.makeSucceededFuture(localAddress.port!)
91+
.bind(host: self.host, port: self.port)
92+
.get()
93+
94+
self.channel = channel
95+
guard let localAddress = channel.localAddress else {
96+
throw ServerError.cantBind
8897
}
98+
self.logger.info("\(self) started and listening on \(localAddress)")
99+
return localAddress.port!
89100
}
90101

91-
func stop() -> EventLoopFuture<Void> {
102+
fileprivate func stop() async throws {
92103
self.logger.info("stopping \(self)")
93-
guard let channel = self.channel else {
94-
return self.group.next().makeFailedFuture(ServerError.notReady)
95-
}
96-
return channel.close().always { _ in
97-
self.shutdown = true
98-
self.logger.info("\(self) stopped")
99-
}
104+
let channel = self.channel!
105+
try? await channel.close().get()
106+
self.shutdown = true
107+
self.logger.info("\(self) stopped")
100108
}
101109
}
102110

@@ -221,32 +229,37 @@ final class HTTPHandler: ChannelInboundHandler {
221229
}
222230
let head = HTTPResponseHead(version: HTTPVersion(major: 1, minor: 1), status: status, headers: headers)
223231

232+
let logger = self.logger
224233
context.write(wrapOutboundOut(.head(head))).whenFailure { error in
225-
self.logger.error("\(self) write error \(error)")
234+
logger.error("write error \(error)")
226235
}
227236

228237
if let b = body {
229238
var buffer = context.channel.allocator.buffer(capacity: b.utf8.count)
230239
buffer.writeString(b)
231240
context.write(wrapOutboundOut(.body(.byteBuffer(buffer)))).whenFailure { error in
232-
self.logger.error("\(self) write error \(error)")
241+
logger.error("write error \(error)")
233242
}
234243
}
235244

245+
let loopBoundContext = NIOLoopBound(context, eventLoop: context.eventLoop)
246+
247+
let keepAlive = self.keepAlive
236248
context.writeAndFlush(wrapOutboundOut(.end(nil))).whenComplete { result in
237249
if case .failure(let error) = result {
238-
self.logger.error("\(self) write error \(error)")
250+
logger.error("write error \(error)")
239251
}
240-
if !self.keepAlive {
252+
if !keepAlive {
253+
let context = loopBoundContext.value
241254
context.close().whenFailure { error in
242-
self.logger.error("\(self) close error \(error)")
255+
logger.error("close error \(error)")
243256
}
244257
}
245258
}
246259
}
247260
}
248261

249-
protocol LambdaServerBehavior {
262+
protocol LambdaServerBehavior: Sendable {
250263
func getInvocation() -> GetInvocationResult
251264
func processResponse(requestId: String, response: String?) -> Result<Void, ProcessResponseError>
252265
func processError(requestId: String, error: ErrorResponse) -> Result<Void, ProcessErrorError>

0 commit comments

Comments
 (0)