@@ -41,32 +41,69 @@ public enum Lambda {
41
41
self . run ( handler: handler)
42
42
}
43
43
44
+ /// Run a Lambda defined by implementing the `LambdaHandler` protocol via a `LambdaHandlerFactory`.
45
+ ///
46
+ /// - note: This is a blocking operation that will run forever, as it's lifecycle is managed by the AWS Lambda Runtime Engine.
47
+ @inlinable
48
+ public static func run( _ factory: @escaping LambdaHandlerFactory ) {
49
+ self . run ( factory: factory)
50
+ }
51
+
52
+ /// Run a Lambda defined by implementing the `LambdaHandler` protocol via a factory.
53
+ ///
54
+ /// - note: This is a blocking operation that will run forever, as it's lifecycle is managed by the AWS Lambda Runtime Engine.
55
+ @inlinable
56
+ public static func run( _ factory: @escaping ( EventLoop ) throws -> LambdaHandler ) {
57
+ self . run ( factory: factory)
58
+ }
59
+
44
60
// for testing and internal use
45
61
@usableFromInline
46
62
@discardableResult
47
63
internal static func run( configuration: Configuration = . init( ) , closure: @escaping LambdaClosure ) -> LambdaLifecycleResult {
48
- return self . run ( handler: LambdaClosureWrapper ( closure) , configuration: configuration)
64
+ return self . run ( configuration: configuration, handler: LambdaClosureWrapper ( closure) )
65
+ }
66
+
67
+ // for testing and internal use
68
+ @usableFromInline
69
+ @discardableResult
70
+ internal static func run( configuration: Configuration = . init( ) , handler: LambdaHandler ) -> LambdaLifecycleResult {
71
+ return self . run ( configuration: configuration, factory: { _, callback in callback ( . success( handler) ) } )
72
+ }
73
+
74
+ // for testing and internal use
75
+ @usableFromInline
76
+ @discardableResult
77
+ internal static func run( configuration: Configuration = . init( ) , factory: @escaping ( EventLoop ) throws -> LambdaHandler ) -> LambdaLifecycleResult {
78
+ return self . run ( configuration: configuration, factory: { ( eventloop: EventLoop , callback: ( Result < LambdaHandler , Error > ) -> Void ) -> Void in
79
+ do {
80
+ let handler = try factory ( eventloop)
81
+ callback ( . success( handler) )
82
+ } catch {
83
+ callback ( . failure( error) )
84
+ }
85
+ } )
49
86
}
50
87
51
88
// for testing and internal use
52
89
@usableFromInline
53
90
@discardableResult
54
- internal static func run( handler : LambdaHandler , configuration: Configuration = . init( ) ) -> LambdaLifecycleResult {
91
+ internal static func run( configuration: Configuration = . init( ) , factory : @escaping LambdaHandlerFactory ) -> LambdaLifecycleResult {
55
92
do {
56
93
let eventLoopGroup = MultiThreadedEventLoopGroup ( numberOfThreads: 1 ) // only need one thread, will improve performance
57
94
defer { try ! eventLoopGroup. syncShutdownGracefully ( ) }
58
- let result = try self . runAsync ( eventLoopGroup: eventLoopGroup, handler : handler , configuration : configuration ) . wait ( )
95
+ let result = try self . runAsync ( eventLoopGroup: eventLoopGroup, configuration : configuration , factory : factory ) . wait ( )
59
96
return . success( result)
60
97
} catch {
61
98
return . failure( error)
62
99
}
63
100
}
64
101
65
- internal static func runAsync( eventLoopGroup: EventLoopGroup , handler : LambdaHandler , configuration : Configuration ) -> EventLoopFuture < Int > {
102
+ internal static func runAsync( eventLoopGroup: EventLoopGroup , configuration : Configuration , factory : @escaping LambdaHandlerFactory ) -> EventLoopFuture < Int > {
66
103
Backtrace . install ( )
67
104
var logger = Logger ( label: " Lambda " )
68
105
logger. logLevel = configuration. general. logLevel
69
- let lifecycle = Lifecycle ( eventLoop: eventLoopGroup. next ( ) , logger: logger, configuration: configuration, handler : handler )
106
+ let lifecycle = Lifecycle ( eventLoop: eventLoopGroup. next ( ) , logger: logger, configuration: configuration, factory : factory )
70
107
let signalSource = trap ( signal: configuration. lifecycle. stopSignal) { signal in
71
108
logger. info ( " intercepted signal: \( signal) " )
72
109
lifecycle. stop ( )
@@ -132,31 +169,33 @@ public enum Lambda {
132
169
private let eventLoop : EventLoop
133
170
private let logger : Logger
134
171
private let configuration : Configuration
135
- private let handler : LambdaHandler
172
+ private let factory : LambdaHandlerFactory
136
173
137
- private var _state = LifecycleState . idle
174
+ private var _state = State . idle
138
175
private let stateLock = Lock ( )
139
176
140
- init ( eventLoop: EventLoop , logger: Logger , configuration: Configuration , handler : LambdaHandler ) {
177
+ init ( eventLoop: EventLoop , logger: Logger , configuration: Configuration , factory : @escaping LambdaHandlerFactory ) {
141
178
self . eventLoop = eventLoop
142
179
self . logger = logger
143
180
self . configuration = configuration
144
- self . handler = handler
181
+ self . factory = factory
145
182
}
146
183
147
184
deinit {
148
- precondition ( self . state == . shutdown, " invalid state \( self . state) " )
185
+ guard case . shutdown = self . state else {
186
+ preconditionFailure ( " invalid state \( self . state) " )
187
+ }
149
188
}
150
189
151
- private var state : LifecycleState {
190
+ private var state : State {
152
191
get {
153
192
return self . stateLock. withLock {
154
193
self . _state
155
194
}
156
195
}
157
196
set {
158
197
self . stateLock. withLockVoid {
159
- precondition ( newValue. rawValue > _state. rawValue , " invalid state \( newValue) after \( self . _state) " )
198
+ precondition ( newValue. order > _state. order , " invalid state \( newValue) after \( self . _state) " )
160
199
self . _state = newValue
161
200
}
162
201
}
@@ -167,10 +206,10 @@ public enum Lambda {
167
206
self . state = . initializing
168
207
var logger = self . logger
169
208
logger [ metadataKey: " lifecycleId " ] = . string( self . configuration. lifecycle. id)
170
- let runner = LambdaRunner ( eventLoop: self . eventLoop, configuration: self . configuration, lambdaHandler : self . handler )
171
- return runner. initialize ( logger: logger) . flatMap { _ in
172
- self . state = . active
173
- return self . run ( runner : runner )
209
+ let runner = LambdaRunner ( eventLoop: self . eventLoop, configuration: self . configuration)
210
+ return runner. initialize ( logger: logger, factory : self . factory ) . flatMap { handler in
211
+ self . state = . active( runner , handler )
212
+ return self . run ( )
174
213
}
175
214
}
176
215
@@ -185,18 +224,18 @@ public enum Lambda {
185
224
}
186
225
187
226
@inline ( __always)
188
- private func run( runner : LambdaRunner ) -> EventLoopFuture < Int > {
227
+ private func run( ) -> EventLoopFuture < Int > {
189
228
let promise = self . eventLoop. makePromise ( of: Int . self)
190
229
191
230
func _run( _ count: Int ) {
192
231
switch self . state {
193
- case . active:
232
+ case . active( let runner , let handler ) :
194
233
if self . configuration. lifecycle. maxTimes > 0 , count >= self . configuration. lifecycle. maxTimes {
195
234
return promise. succeed ( count)
196
235
}
197
236
var logger = self . logger
198
237
logger [ metadataKey: " lifecycleIteration " ] = " \( count) "
199
- runner. run ( logger: logger) . whenComplete { result in
238
+ runner. run ( logger: logger, handler : handler ) . whenComplete { result in
200
239
switch result {
201
240
case . success:
202
241
// recursive! per aws lambda runtime spec the polling requests are to be done one at a time
@@ -216,6 +255,29 @@ public enum Lambda {
216
255
217
256
return promise. futureResult
218
257
}
258
+
259
+ private enum State {
260
+ case idle
261
+ case initializing
262
+ case active( LambdaRunner , LambdaHandler )
263
+ case stopping
264
+ case shutdown
265
+
266
+ internal var order : Int {
267
+ switch self {
268
+ case . idle:
269
+ return 0
270
+ case . initializing:
271
+ return 1
272
+ case . active:
273
+ return 2
274
+ case . stopping:
275
+ return 3
276
+ case . shutdown:
277
+ return 4
278
+ }
279
+ }
280
+ }
219
281
}
220
282
221
283
@usableFromInline
@@ -293,44 +355,26 @@ public enum Lambda {
293
355
return " \( Configuration . self) \n \( self . general) ) \n \( self . lifecycle) \n \( self . runtimeEngine) "
294
356
}
295
357
}
296
-
297
- private enum LifecycleState : Int {
298
- case idle
299
- case initializing
300
- case active
301
- case stopping
302
- case shutdown
303
- }
304
358
}
305
359
306
- /// A result type for a Lambda that returns a `[UInt8]`.
307
360
public typealias LambdaResult = Result < [ UInt8 ] , Error >
308
361
309
362
public typealias LambdaCallback = ( LambdaResult ) -> Void
310
363
311
- /// A processing closure for a Lambda that takes a `[UInt8]` and returns a `LambdaResult` result type asynchronously.
364
+ /// A processing closure for a Lambda that takes a `[UInt8]` and returns a `LambdaResult` result type asynchronously via`LambdaCallback` .
312
365
public typealias LambdaClosure = ( Lambda . Context , [ UInt8 ] , LambdaCallback ) -> Void
313
366
314
- /// A result type for a Lambda initialization.
315
- public typealias LambdaInitResult = Result < Void , Error >
316
-
317
367
/// A callback to provide the result of Lambda initialization.
318
- public typealias LambdaInitCallBack = ( LambdaInitResult ) -> Void
368
+ public typealias LambdaInitCallBack = ( Result < LambdaHandler , Error > ) -> Void
369
+
370
+ public typealias LambdaHandlerFactory = ( EventLoop , LambdaInitCallBack ) -> Void
319
371
320
- /// A processing protocol for a Lambda that takes a `[UInt8]` and returns a `LambdaResult` result type asynchronously.
372
+ /// A processing protocol for a Lambda that takes a `[UInt8]` and returns a `LambdaResult` result type asynchronously via `LambdaCallback` .
321
373
public protocol LambdaHandler {
322
- /// Initializes the `LambdaHandler`.
323
- func initialize( callback: @escaping LambdaInitCallBack )
374
+ /// Handles the Lambda request.
324
375
func handle( context: Lambda . Context , payload: [ UInt8 ] , callback: @escaping LambdaCallback )
325
376
}
326
377
327
- extension LambdaHandler {
328
- @inlinable
329
- public func initialize( callback: @escaping LambdaInitCallBack ) {
330
- callback ( . success( ( ) ) )
331
- }
332
- }
333
-
334
378
@usableFromInline
335
379
internal typealias LambdaLifecycleResult = Result < Int , Error >
336
380
0 commit comments