@@ -17,17 +17,30 @@ import NIO
17
17
import NIOConcurrencyHelpers
18
18
19
19
extension Lambda {
20
- internal final class Lifecycle {
20
+ /// `Lifecycle` manages the Lambda process lifecycle.
21
+ public final class Lifecycle {
21
22
private let eventLoop : EventLoop
23
+ private let shutdownPromise : EventLoopPromise < Int >
22
24
private let logger : Logger
23
25
private let configuration : Configuration
24
26
private let factory : LambdaHandlerFactory
25
27
26
28
private var _state = State . idle
27
29
private let stateLock = Lock ( )
28
30
31
+ /// Create a new `Lifecycle`.
32
+ ///
33
+ /// - parameters:
34
+ /// - eventLoop: An `EventLoop` to run the Lambda on.
35
+ /// - logger: A `Logger` to log the Lambda events.
36
+ /// - factory: A `LambdaHandlerFactory` to create the concrete Lambda handler.
37
+ public convenience init ( eventLoop: EventLoop , logger: Logger , factory: @escaping LambdaHandlerFactory ) {
38
+ self . init ( eventLoop: eventLoop, logger: logger, configuration: . init( ) , factory: factory)
39
+ }
40
+
29
41
init ( eventLoop: EventLoop , logger: Logger , configuration: Configuration , factory: @escaping LambdaHandlerFactory ) {
30
42
self . eventLoop = eventLoop
43
+ self . shutdownPromise = eventLoop. makePromise ( of: Int . self)
31
44
self . logger = logger
32
45
self . configuration = configuration
33
46
self . factory = factory
@@ -39,46 +52,46 @@ extension Lambda {
39
52
}
40
53
}
41
54
42
- private var state : State {
43
- get {
44
- self . stateLock. withLock {
45
- self . _state
46
- }
47
- }
48
- set {
49
- self . stateLock. withLockVoid {
50
- precondition ( newValue. order > _state. order, " invalid state \( newValue) after \( self . _state) " )
51
- self . _state = newValue
52
- }
53
- }
55
+ /// The `Lifecycle` shutdown future.
56
+ ///
57
+ /// - Returns: An `EventLoopFuture` that is fulfilled after the Lambda lifecycle has fully shutdown.
58
+ public var shutdownFuture : EventLoopFuture < Int > {
59
+ self . shutdownPromise. futureResult
54
60
}
55
61
56
- func start( ) -> EventLoopFuture < Int > {
62
+ /// Start the `Lifecycle`.
63
+ ///
64
+ /// - Returns: An `EventLoopFuture` that is fulfilled after the Lambda hander has been created and initiliazed, and a first run has been schduled.
65
+ public func start( ) -> EventLoopFuture < Void > {
57
66
logger. info ( " lambda lifecycle starting with \( self . configuration) " )
58
67
self . state = . initializing
68
+ // triggered when the Lambda has finished its last run
69
+ let finishedPromise = self . eventLoop. makePromise ( of: Int . self)
70
+ finishedPromise. futureResult. always { _ in
71
+ self . markShutdown ( )
72
+ } . cascade ( to: self . shutdownPromise)
59
73
var logger = self . logger
60
74
logger [ metadataKey: " lifecycleId " ] = . string( self . configuration. lifecycle. id)
61
75
let runner = Runner ( eventLoop: self . eventLoop, configuration: self . configuration)
62
- return runner. initialize ( logger: logger, factory: self . factory) . flatMap { handler in
76
+ return runner. initialize ( logger: logger, factory: self . factory) . map { handler in
63
77
self . state = . active( runner, handler)
64
- return self . run ( )
78
+ self . run ( promise : finishedPromise )
65
79
}
66
80
}
67
81
68
- func stop( ) {
69
- self . logger. debug ( " lambda lifecycle stopping " )
70
- self . state = . stopping
82
+ // MARK: - Private
83
+
84
+ /// Begin the `Lifecycle` shutdown.
85
+ public func shutdown( ) {
86
+ self . state = . shuttingdown
71
87
}
72
88
73
- func shutdown( ) {
74
- self . logger. debug ( " lambda lifecycle shutdown " )
89
+ private func markShutdown( ) {
75
90
self . state = . shutdown
76
91
}
77
92
78
93
@inline ( __always)
79
- private func run( ) -> EventLoopFuture < Int > {
80
- let promise = self . eventLoop. makePromise ( of: Int . self)
81
-
94
+ private func run( promise: EventLoopPromise < Int > ) {
82
95
func _run( _ count: Int ) {
83
96
switch self . state {
84
97
case . active( let runner, let handler) :
@@ -96,23 +109,36 @@ extension Lambda {
96
109
promise. fail ( error)
97
110
}
98
111
}
99
- case . stopping , . shutdown :
112
+ case . shuttingdown :
100
113
promise. succeed ( count)
101
114
default :
102
115
preconditionFailure ( " invalid run state: \( self . state) " )
103
116
}
104
117
}
105
118
106
119
_run ( 0 )
120
+ }
107
121
108
- return promise. futureResult
122
+ private var state : State {
123
+ get {
124
+ self . stateLock. withLock {
125
+ self . _state
126
+ }
127
+ }
128
+ set {
129
+ self . stateLock. withLockVoid {
130
+ precondition ( newValue. order > self . _state. order, " invalid state \( newValue) after \( self . _state) " )
131
+ self . _state = newValue
132
+ }
133
+ self . logger. debug ( " lambda lifecycle state: \( newValue) " )
134
+ }
109
135
}
110
136
111
137
private enum State {
112
138
case idle
113
139
case initializing
114
140
case active( Runner , ByteBufferLambdaHandler )
115
- case stopping
141
+ case shuttingdown
116
142
case shutdown
117
143
118
144
internal var order : Int {
@@ -123,7 +149,7 @@ extension Lambda {
123
149
return 1
124
150
case . active:
125
151
return 2
126
- case . stopping :
152
+ case . shuttingdown :
127
153
return 3
128
154
case . shutdown:
129
155
return 4
0 commit comments