@@ -21,11 +21,7 @@ import Backtrace
21
21
import Dispatch
22
22
import Logging
23
23
24
- // MARK: - Lifecycle (namespace)
25
-
26
- public enum Lifecycle {
27
- public typealias Task = LifecycleTask
28
- }
24
+ // MARK: - LifecycleTask
29
25
30
26
/// Represents an item that can be started and shut down
31
27
public protocol LifecycleTask {
@@ -34,87 +30,52 @@ public protocol LifecycleTask {
34
30
func shutdown( _ callback: @escaping ( Error ? ) -> Void )
35
31
}
36
32
37
- /// Supported startup and shutdown method styles
38
- public extension Lifecycle {
39
- struct Handler {
40
- private let body : ( @escaping ( Error ? ) -> Void ) -> Void
41
-
42
- /// Initialize a `Lifecycle.Handler` based on a completion handler.
43
- ///
44
- /// - parameters:
45
- /// - callback: the underlying completion handler
46
- public init ( _ callback: @escaping ( @escaping ( Error ? ) -> Void ) -> Void ) {
47
- self . body = callback
48
- }
49
-
50
- /// Asynchronous `Lifecycle.Handler` based on a completion handler.
51
- ///
52
- /// - parameters:
53
- /// - callback: the underlying completion handler
54
- public static func async ( _ callback: @escaping ( @escaping ( Error ? ) -> Void ) -> Void ) -> Handler {
55
- return Handler ( callback)
56
- }
57
-
58
- /// Asynchronous `Lifecycle.Handler` based on a blocking, throwing function.
59
- ///
60
- /// - parameters:
61
- /// - body: the underlying function
62
- public static func sync( _ body: @escaping ( ) throws -> Void ) -> Handler {
63
- return Handler { completionHandler in
64
- do {
65
- try body ( )
66
- completionHandler ( nil )
67
- } catch {
68
- completionHandler ( error)
69
- }
70
- }
71
- }
33
+ // MARK: - LifecycleHandler
72
34
73
- /// Noop `Lifecycle.Handler`.
74
- public static var none : Handler {
75
- return Handler { callback in
76
- callback ( nil )
77
- }
78
- }
35
+ /// Supported startup and shutdown method styles
36
+ public struct LifecycleHandler {
37
+ private let body : ( @escaping ( Error ? ) -> Void ) -> Void
79
38
80
- internal func run( _ callback: @escaping ( Error ? ) -> Void ) {
81
- self . body ( callback)
82
- }
39
+ /// Initialize a `Lifecycle.Handler` based on a completion handler.
40
+ ///
41
+ /// - parameters:
42
+ /// - callback: the underlying completion handler
43
+ public init ( _ callback: @escaping ( @escaping ( Error ? ) -> Void ) -> Void ) {
44
+ self . body = callback
83
45
}
84
- }
85
46
86
- public extension Lifecycle {
87
- struct ShutdownError : Error {
88
- public let errors : [ String : Error ]
47
+ /// Asynchronous `Lifecycle.Handler` based on a completion handler.
48
+ ///
49
+ /// - parameters:
50
+ /// - callback: the underlying completion handler
51
+ public static func async ( _ callback: @escaping ( @escaping ( Error ? ) -> Void ) -> Void ) -> LifecycleHandler {
52
+ return LifecycleHandler ( callback)
89
53
}
90
- }
91
54
92
- extension Lifecycle {
93
- /// Setup a signal trap.
55
+ /// Asynchronous `Lifecycle.Handler` based on a blocking, throwing function.
94
56
///
95
57
/// - parameters:
96
- /// - signal: The signal to trap.
97
- /// - handler: closure to invoke when the signal is captured.
98
- /// - returns: a `DispatchSourceSignal` for the given trap. The source must be cancled by the caller.
99
- public static func trap( signal sig: Signal , handler: @escaping ( Signal ) -> Void , on queue: DispatchQueue = . global( ) ) -> DispatchSourceSignal {
100
- let signalSource = DispatchSource . makeSignalSource ( signal: sig. rawValue, queue: queue)
101
- signal ( sig. rawValue, SIG_IGN)
102
- signalSource. setEventHandler ( handler: {
103
- signalSource. cancel ( )
104
- handler ( sig)
105
- } )
106
- signalSource. resume ( )
107
- return signalSource
58
+ /// - body: the underlying function
59
+ public static func sync( _ body: @escaping ( ) throws -> Void ) -> LifecycleHandler {
60
+ return LifecycleHandler { completionHandler in
61
+ do {
62
+ try body ( )
63
+ completionHandler ( nil )
64
+ } catch {
65
+ completionHandler ( error)
66
+ }
67
+ }
108
68
}
109
69
110
- /// A system signal
111
- public struct Signal {
112
- internal var rawValue : CInt
70
+ /// Noop `Lifecycle.Handler`.
71
+ public static var none : LifecycleHandler {
72
+ return LifecycleHandler { callback in
73
+ callback ( nil )
74
+ }
75
+ }
113
76
114
- public static let TERM : Signal = Signal ( rawValue: SIGTERM)
115
- public static let INT : Signal = Signal ( rawValue: SIGINT)
116
- // for testing
117
- internal static let ALRM : Signal = Signal ( rawValue: SIGALRM)
77
+ internal func run( _ callback: @escaping ( Error ? ) -> Void ) {
78
+ self . body ( callback)
118
79
}
119
80
}
120
81
@@ -146,7 +107,7 @@ public struct ServiceLifecycle {
146
107
public func start( _ callback: @escaping ( Error ? ) -> Void ) {
147
108
self . configuration. shutdownSignal? . forEach { signal in
148
109
self . lifecycle. log ( " setting up shutdown hook on \( signal) " )
149
- let signalSource = Lifecycle . trap ( signal: signal, handler: { signal in
110
+ let signalSource = ServiceLifecycle . trap ( signal: signal, handler: { signal in
150
111
self . lifecycle. log ( " intercepted signal: \( signal) " )
151
112
self . shutdown ( )
152
113
} )
@@ -181,20 +142,49 @@ public struct ServiceLifecycle {
181
142
}
182
143
}
183
144
145
+ extension ServiceLifecycle {
146
+ /// Setup a signal trap.
147
+ ///
148
+ /// - parameters:
149
+ /// - signal: The signal to trap.
150
+ /// - handler: closure to invoke when the signal is captured.
151
+ /// - returns: a `DispatchSourceSignal` for the given trap. The source must be cancled by the caller.
152
+ public static func trap( signal sig: Signal , handler: @escaping ( Signal ) -> Void , on queue: DispatchQueue = . global( ) ) -> DispatchSourceSignal {
153
+ let signalSource = DispatchSource . makeSignalSource ( signal: sig. rawValue, queue: queue)
154
+ signal ( sig. rawValue, SIG_IGN)
155
+ signalSource. setEventHandler ( handler: {
156
+ signalSource. cancel ( )
157
+ handler ( sig)
158
+ } )
159
+ signalSource. resume ( )
160
+ return signalSource
161
+ }
162
+
163
+ /// A system signal
164
+ public struct Signal {
165
+ internal var rawValue : CInt
166
+
167
+ public static let TERM : Signal = Signal ( rawValue: SIGTERM)
168
+ public static let INT : Signal = Signal ( rawValue: SIGINT)
169
+ // for testing
170
+ internal static let ALRM : Signal = Signal ( rawValue: SIGALRM)
171
+ }
172
+ }
173
+
184
174
public extension ServiceLifecycle {
185
175
/// Adds a `Task` to a `Tasks` collection.
186
176
///
187
177
/// - parameters:
188
178
/// - tasks: one or more `Tasks`.
189
- func register( _ tasks: Lifecycle . Task ... ) {
179
+ func register( _ tasks: LifecycleTask ... ) {
190
180
self . lifecycle. register ( tasks)
191
181
}
192
182
193
183
/// Adds a `Task` to a `Tasks` collection.
194
184
///
195
185
/// - parameters:
196
186
/// - tasks: array of `Tasks`.
197
- func register( _ tasks: [ Lifecycle . Task ] ) {
187
+ func register( _ tasks: [ LifecycleTask ] ) {
198
188
self . lifecycle. register ( tasks)
199
189
}
200
190
@@ -204,7 +194,7 @@ public extension ServiceLifecycle {
204
194
/// - label: label of the item, useful for debugging.
205
195
/// - start: `Handler` to perform the startup.
206
196
/// - shutdown: `Handler` to perform the shutdown.
207
- func register( label: String , start: Lifecycle . Handler , shutdown: Lifecycle . Handler ) {
197
+ func register( label: String , start: LifecycleHandler , shutdown: LifecycleHandler ) {
208
198
self . lifecycle. register ( label: label, start: start, shutdown: shutdown)
209
199
}
210
200
@@ -213,7 +203,7 @@ public extension ServiceLifecycle {
213
203
/// - parameters:
214
204
/// - label: label of the item, useful for debugging.
215
205
/// - handler: `Handler` to perform the shutdown.
216
- func registerShutdown( label: String , _ handler: Lifecycle . Handler ) {
206
+ func registerShutdown( label: String , _ handler: LifecycleHandler ) {
217
207
self . lifecycle. registerShutdown ( label: label, handler)
218
208
}
219
209
@@ -245,13 +235,13 @@ extension ServiceLifecycle {
245
235
/// Defines the `DispatchQueue` on which startup and shutdown callback handlers are run.
246
236
public var callbackQueue : DispatchQueue
247
237
/// Defines if to install a crash signal trap that prints backtraces.
248
- public var shutdownSignal : [ Lifecycle . Signal ] ?
238
+ public var shutdownSignal : [ Signal ] ?
249
239
/// Defines what, if any, signals to trap for invoking shutdown.
250
240
public var installBacktrace : Bool
251
241
252
242
public init ( logger: Logger = Logger ( label: " Lifeycle " ) ,
253
243
callbackQueue: DispatchQueue = . global( ) ,
254
- shutdownSignal: [ Lifecycle . Signal ] ? = [ . TERM, . INT] ,
244
+ shutdownSignal: [ Signal ] ? = [ . TERM, . INT] ,
255
245
installBacktrace: Bool = true ) {
256
246
self . logger = logger
257
247
self . callbackQueue = callbackQueue
@@ -261,18 +251,22 @@ extension ServiceLifecycle {
261
251
}
262
252
}
263
253
254
+ struct ShutdownError : Error {
255
+ public let errors : [ String : Error ]
256
+ }
257
+
264
258
// MARK: - ComponentLifecycle
265
259
266
260
/// `Lifecycle` provides a basic mechanism to cleanly startup and shutdown the application, freeing resources in order before exiting.
267
- public class ComponentLifecycle : Lifecycle . Task {
261
+ public class ComponentLifecycle : LifecycleTask {
268
262
public let label : String
269
263
private let logger : Logger
270
264
internal let shutdownGroup = DispatchGroup ( )
271
265
272
266
private var state = State . idle
273
267
private let stateLock = Lock ( )
274
268
275
- private var tasks = [ Lifecycle . Task ] ( )
269
+ private var tasks = [ LifecycleTask ] ( )
276
270
private let tasksLock = Lock ( )
277
271
278
272
/// Creates a `ComponentLifecycle` instance.
@@ -369,7 +363,7 @@ public class ComponentLifecycle: Lifecycle.Task {
369
363
370
364
// MARK: - private
371
365
372
- private func _start( on queue: DispatchQueue , tasks: [ Lifecycle . Task ] , callback: @escaping ( Error ? ) -> Void ) {
366
+ private func _start( on queue: DispatchQueue , tasks: [ LifecycleTask ] , callback: @escaping ( Error ? ) -> Void ) {
373
367
precondition ( tasks. count > 0 , " invalid number of tasks, must be > 0 " )
374
368
self . stateLock. withLock {
375
369
guard case . idle = self . state else {
@@ -402,7 +396,7 @@ public class ComponentLifecycle: Lifecycle.Task {
402
396
}
403
397
}
404
398
405
- private func startTask( on queue: DispatchQueue , tasks: [ Lifecycle . Task ] , index: Int , callback: @escaping ( Int , Error ? ) -> Void ) {
399
+ private func startTask( on queue: DispatchQueue , tasks: [ LifecycleTask ] , index: Int , callback: @escaping ( Int , Error ? ) -> Void ) {
406
400
// async barrier
407
401
let start = { ( callback) -> Void in queue. async { tasks [ index] . start ( callback) } }
408
402
let callback = { ( index, error) -> Void in queue. async { callback ( index, error) } }
@@ -424,7 +418,7 @@ public class ComponentLifecycle: Lifecycle.Task {
424
418
}
425
419
}
426
420
427
- private func _shutdown( on queue: DispatchQueue , tasks: [ Lifecycle . Task ] , callback: @escaping ( ) -> Void ) {
421
+ private func _shutdown( on queue: DispatchQueue , tasks: [ LifecycleTask ] , callback: @escaping ( ) -> Void ) {
428
422
self . stateLock. withLock {
429
423
log ( " shutting down " )
430
424
self . state = . shuttingDown( queue)
@@ -441,7 +435,7 @@ public class ComponentLifecycle: Lifecycle.Task {
441
435
}
442
436
}
443
437
444
- private func shutdownTask( on queue: DispatchQueue , tasks: [ Lifecycle . Task ] , index: Int , errors: [ String : Error ] ? , callback: @escaping ( [ String : Error ] ? ) -> Void ) {
438
+ private func shutdownTask( on queue: DispatchQueue , tasks: [ LifecycleTask ] , index: Int , errors: [ String : Error ] ? , callback: @escaping ( [ String : Error ] ? ) -> Void ) {
445
439
// async barrier
446
440
let shutdown = { ( callback) -> Void in queue. async { tasks [ index] . shutdown ( callback) } }
447
441
let callback = { ( errors) -> Void in queue. async { callback ( errors) } }
@@ -470,17 +464,17 @@ public class ComponentLifecycle: Lifecycle.Task {
470
464
private enum State {
471
465
case idle
472
466
case starting( DispatchQueue )
473
- case started( DispatchQueue , [ Lifecycle . Task ] )
467
+ case started( DispatchQueue , [ LifecycleTask ] )
474
468
case shuttingDown( DispatchQueue )
475
469
case shutdown( [ String : Error ] ? )
476
470
}
477
471
}
478
472
479
473
public extension ComponentLifecycle {
480
- internal struct Task : Lifecycle . Task {
474
+ internal struct Task : LifecycleTask {
481
475
let label : String
482
- let start : Lifecycle . Handler
483
- let shutdown : Lifecycle . Handler
476
+ let start : LifecycleHandler
477
+ let shutdown : LifecycleHandler
484
478
485
479
func start( _ callback: @escaping ( Error ? ) -> Void ) {
486
480
self . start. run ( callback)
@@ -495,15 +489,15 @@ public extension ComponentLifecycle {
495
489
///
496
490
/// - parameters:
497
491
/// - tasks: one or more `Tasks`.
498
- func register( _ tasks: Lifecycle . Task ... ) {
492
+ func register( _ tasks: LifecycleTask ... ) {
499
493
self . register ( tasks)
500
494
}
501
495
502
496
/// Adds a `Task` to a `Tasks` collection.
503
497
///
504
498
/// - parameters:
505
499
/// - tasks: array of `Tasks`.
506
- func register( _ tasks: [ Lifecycle . Task ] ) {
500
+ func register( _ tasks: [ LifecycleTask ] ) {
507
501
self . stateLock. withLock {
508
502
guard case . idle = self . state else {
509
503
preconditionFailure ( " invalid state, \( self . state) " )
@@ -520,7 +514,7 @@ public extension ComponentLifecycle {
520
514
/// - label: label of the item, useful for debugging.
521
515
/// - start: `Handler` to perform the startup.
522
516
/// - shutdown: `Handler` to perform the shutdown.
523
- func register( label: String , start: Lifecycle . Handler , shutdown: Lifecycle . Handler ) {
517
+ func register( label: String , start: LifecycleHandler , shutdown: LifecycleHandler ) {
524
518
self . register ( Task ( label: label, start: start, shutdown: shutdown) )
525
519
}
526
520
@@ -529,7 +523,7 @@ public extension ComponentLifecycle {
529
523
/// - parameters:
530
524
/// - label: label of the item, useful for debugging.
531
525
/// - handler: `Handler` to perform the shutdown.
532
- func registerShutdown( label: String , _ handler: Lifecycle . Handler ) {
526
+ func registerShutdown( label: String , _ handler: LifecycleHandler ) {
533
527
self . register ( label: label, start: . none, shutdown: handler)
534
528
}
535
529
0 commit comments