@@ -41,32 +41,47 @@ public enum Lambda {
41
41
self . run ( handler: handler)
42
42
}
43
43
44
+ /// Run a Lambda defined by implementing the `LambdaHandler` protocol.
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( _ provider: @escaping LambdaHandlerProvider ) {
49
+ self . run ( provider: provider)
50
+ }
51
+
44
52
// for testing and internal use
45
53
@usableFromInline
46
54
@discardableResult
47
55
internal static func run( configuration: Configuration = . init( ) , closure: @escaping LambdaClosure ) -> LambdaLifecycleResult {
48
- return self . run ( handler: LambdaClosureWrapper ( closure) , configuration : configuration )
56
+ return self . run ( configuration : configuration , handler: LambdaClosureWrapper ( closure) )
49
57
}
50
58
51
59
// for testing and internal use
52
60
@usableFromInline
53
61
@discardableResult
54
- internal static func run( handler: LambdaHandler , configuration: Configuration = . init( ) ) -> LambdaLifecycleResult {
62
+ internal static func run( configuration: Configuration = . init( ) , handler: LambdaHandler ) -> LambdaLifecycleResult {
63
+ return self . run ( configuration: configuration, provider: { _ in handler } )
64
+ }
65
+
66
+ // for testing and internal use
67
+ @usableFromInline
68
+ @discardableResult
69
+ internal static func run( configuration: Configuration = . init( ) , provider: @escaping LambdaHandlerProvider ) -> LambdaLifecycleResult {
55
70
do {
56
71
let eventLoopGroup = MultiThreadedEventLoopGroup ( numberOfThreads: 1 ) // only need one thread, will improve performance
57
72
defer { try ! eventLoopGroup. syncShutdownGracefully ( ) }
58
- let result = try self . runAsync ( eventLoopGroup: eventLoopGroup, handler : handler , configuration : configuration ) . wait ( )
73
+ let result = try self . runAsync ( eventLoopGroup: eventLoopGroup, configuration : configuration , provider : provider ) . wait ( )
59
74
return . success( result)
60
75
} catch {
61
76
return . failure( error)
62
77
}
63
78
}
64
79
65
- internal static func runAsync( eventLoopGroup: EventLoopGroup , handler : LambdaHandler , configuration : Configuration ) -> EventLoopFuture < Int > {
80
+ internal static func runAsync( eventLoopGroup: EventLoopGroup , configuration : Configuration , provider : @escaping LambdaHandlerProvider ) -> EventLoopFuture < Int > {
66
81
Backtrace . install ( )
67
82
var logger = Logger ( label: " Lambda " )
68
83
logger. logLevel = configuration. general. logLevel
69
- let lifecycle = Lifecycle ( eventLoop: eventLoopGroup. next ( ) , logger: logger, configuration: configuration, handler : handler )
84
+ let lifecycle = Lifecycle ( eventLoop: eventLoopGroup. next ( ) , logger: logger, configuration: configuration, provider : provider )
70
85
let signalSource = trap ( signal: configuration. lifecycle. stopSignal) { signal in
71
86
logger. info ( " intercepted signal: \( signal) " )
72
87
lifecycle. stop ( )
@@ -113,31 +128,33 @@ public enum Lambda {
113
128
private let eventLoop : EventLoop
114
129
private let logger : Logger
115
130
private let configuration : Configuration
116
- private let handler : LambdaHandler
131
+ private let provider : LambdaHandlerProvider
117
132
118
- private var _state = LifecycleState . idle
133
+ private var _state = State . idle
119
134
private let stateLock = Lock ( )
120
135
121
- init ( eventLoop: EventLoop , logger: Logger , configuration: Configuration , handler : LambdaHandler ) {
136
+ init ( eventLoop: EventLoop , logger: Logger , configuration: Configuration , provider : @escaping LambdaHandlerProvider ) {
122
137
self . eventLoop = eventLoop
123
138
self . logger = logger
124
139
self . configuration = configuration
125
- self . handler = handler
140
+ self . provider = provider
126
141
}
127
142
128
143
deinit {
129
- precondition ( self . state == . shutdown, " invalid state \( self . state) " )
144
+ guard case . shutdown = self . state else {
145
+ preconditionFailure ( " invalid state \( self . state) " )
146
+ }
130
147
}
131
148
132
- private var state : LifecycleState {
149
+ private var state : State {
133
150
get {
134
151
return self . stateLock. withLock {
135
152
self . _state
136
153
}
137
154
}
138
155
set {
139
156
self . stateLock. withLockVoid {
140
- precondition ( newValue. rawValue > _state. rawValue , " invalid state \( newValue) after \( self . _state) " )
157
+ precondition ( newValue. order > _state. order , " invalid state \( newValue) after \( self . _state) " )
141
158
self . _state = newValue
142
159
}
143
160
}
@@ -148,10 +165,10 @@ public enum Lambda {
148
165
self . state = . initializing
149
166
var logger = self . logger
150
167
logger [ metadataKey: " lifecycleId " ] = . string( self . configuration. lifecycle. id)
151
- let runner = LambdaRunner ( eventLoop: self . eventLoop, configuration: self . configuration, lambdaHandler : self . handler )
152
- return runner. initialize ( logger: logger) . flatMap { _ in
153
- self . state = . active
154
- return self . run ( runner : runner )
168
+ let runner = LambdaRunner ( eventLoop: self . eventLoop, configuration: self . configuration)
169
+ return runner. initialize ( logger: logger, provider : self . provider ) . flatMap { handler in
170
+ self . state = . active( runner , handler )
171
+ return self . run ( )
155
172
}
156
173
}
157
174
@@ -166,18 +183,18 @@ public enum Lambda {
166
183
}
167
184
168
185
@inline ( __always)
169
- private func run( runner : LambdaRunner ) -> EventLoopFuture < Int > {
186
+ private func run( ) -> EventLoopFuture < Int > {
170
187
let promise = self . eventLoop. makePromise ( of: Int . self)
171
188
172
189
func _run( _ count: Int ) {
173
190
switch self . state {
174
- case . active:
191
+ case . active( let runner , let handler ) :
175
192
if self . configuration. lifecycle. maxTimes > 0 , count >= self . configuration. lifecycle. maxTimes {
176
193
return promise. succeed ( count)
177
194
}
178
195
var logger = self . logger
179
196
logger [ metadataKey: " lifecycleIteration " ] = " \( count) "
180
- runner. run ( logger: logger) . whenComplete { result in
197
+ runner. run ( logger: logger, handler : handler ) . whenComplete { result in
181
198
switch result {
182
199
case . success:
183
200
// recursive! per aws lambda runtime spec the polling requests are to be done one at a time
@@ -197,6 +214,29 @@ public enum Lambda {
197
214
198
215
return promise. futureResult
199
216
}
217
+
218
+ private enum State {
219
+ case idle
220
+ case initializing
221
+ case active( LambdaRunner , LambdaHandler )
222
+ case stopping
223
+ case shutdown
224
+
225
+ internal var order : Int {
226
+ switch self {
227
+ case . idle:
228
+ return 0
229
+ case . initializing:
230
+ return 1
231
+ case . active:
232
+ return 2
233
+ case . stopping:
234
+ return 3
235
+ case . shutdown:
236
+ return 4
237
+ }
238
+ }
239
+ }
200
240
}
201
241
202
242
@usableFromInline
@@ -274,14 +314,6 @@ public enum Lambda {
274
314
return " \( Configuration . self) \n \( self . general) ) \n \( self . lifecycle) \n \( self . runtimeEngine) "
275
315
}
276
316
}
277
-
278
- private enum LifecycleState : Int {
279
- case idle
280
- case initializing
281
- case active
282
- case stopping
283
- case shutdown
284
- }
285
317
}
286
318
287
319
/// A result type for a Lambda that returns a `[UInt8]`.
@@ -298,18 +330,17 @@ public typealias LambdaInitResult = Result<Void, Error>
298
330
/// A callback to provide the result of Lambda initialization.
299
331
public typealias LambdaInitCallBack = ( LambdaInitResult ) -> Void
300
332
333
+ public typealias LambdaHandlerProvider = ( EventLoop ) throws -> LambdaHandler
334
+
301
335
/// A processing protocol for a Lambda that takes a `[UInt8]` and returns a `LambdaResult` result type asynchronously.
302
336
public protocol LambdaHandler {
303
- /// Initializes the `LambdaHandler`.
304
- func initialize( callback: @escaping LambdaInitCallBack )
337
+ /// Handles the Lambda request.
305
338
func handle( context: Lambda . Context , payload: [ UInt8 ] , callback: @escaping LambdaCallback )
306
339
}
307
340
308
- extension LambdaHandler {
309
- @inlinable
310
- public func initialize( callback: @escaping LambdaInitCallBack ) {
311
- callback ( . success( ( ) ) )
312
- }
341
+ public protocol BootstrappedLambdaHandler : LambdaHandler {
342
+ /// Bootstraps the `LambdaHandler`.
343
+ func bootstrap( callback: @escaping LambdaInitCallBack )
313
344
}
314
345
315
346
@usableFromInline
0 commit comments