@@ -21,11 +21,7 @@ import Backtrace
2121import Dispatch
2222import Logging
2323
24- // MARK: - Lifecycle (namespace)
25-
26- public enum Lifecycle {
27- public typealias Task = LifecycleTask
28- }
24+ // MARK: - LifecycleTask
2925
3026/// Represents an item that can be started and shut down
3127public protocol LifecycleTask {
@@ -34,87 +30,52 @@ public protocol LifecycleTask {
3430 func shutdown( _ callback: @escaping ( Error ? ) -> Void )
3531}
3632
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
7234
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
7938
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
8345 }
84- }
8546
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)
8953 }
90- }
9154
92- extension Lifecycle {
93- /// Setup a signal trap.
55+ /// Asynchronous `Lifecycle.Handler` based on a blocking, throwing function.
9456 ///
9557 /// - 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+ }
10868 }
10969
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+ }
11376
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)
11879 }
11980}
12081
@@ -146,7 +107,7 @@ public struct ServiceLifecycle {
146107 public func start( _ callback: @escaping ( Error ? ) -> Void ) {
147108 self . configuration. shutdownSignal? . forEach { signal in
148109 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
150111 self . lifecycle. log ( " intercepted signal: \( signal) " )
151112 self . shutdown ( )
152113 } )
@@ -181,20 +142,49 @@ public struct ServiceLifecycle {
181142 }
182143}
183144
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+
184174public extension ServiceLifecycle {
185175 /// Adds a `Task` to a `Tasks` collection.
186176 ///
187177 /// - parameters:
188178 /// - tasks: one or more `Tasks`.
189- func register( _ tasks: Lifecycle . Task ... ) {
179+ func register( _ tasks: LifecycleTask ... ) {
190180 self . lifecycle. register ( tasks)
191181 }
192182
193183 /// Adds a `Task` to a `Tasks` collection.
194184 ///
195185 /// - parameters:
196186 /// - tasks: array of `Tasks`.
197- func register( _ tasks: [ Lifecycle . Task ] ) {
187+ func register( _ tasks: [ LifecycleTask ] ) {
198188 self . lifecycle. register ( tasks)
199189 }
200190
@@ -204,7 +194,7 @@ public extension ServiceLifecycle {
204194 /// - label: label of the item, useful for debugging.
205195 /// - start: `Handler` to perform the startup.
206196 /// - 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 ) {
208198 self . lifecycle. register ( label: label, start: start, shutdown: shutdown)
209199 }
210200
@@ -213,7 +203,7 @@ public extension ServiceLifecycle {
213203 /// - parameters:
214204 /// - label: label of the item, useful for debugging.
215205 /// - handler: `Handler` to perform the shutdown.
216- func registerShutdown( label: String , _ handler: Lifecycle . Handler ) {
206+ func registerShutdown( label: String , _ handler: LifecycleHandler ) {
217207 self . lifecycle. registerShutdown ( label: label, handler)
218208 }
219209
@@ -245,13 +235,13 @@ extension ServiceLifecycle {
245235 /// Defines the `DispatchQueue` on which startup and shutdown callback handlers are run.
246236 public var callbackQueue : DispatchQueue
247237 /// Defines if to install a crash signal trap that prints backtraces.
248- public var shutdownSignal : [ Lifecycle . Signal ] ?
238+ public var shutdownSignal : [ Signal ] ?
249239 /// Defines what, if any, signals to trap for invoking shutdown.
250240 public var installBacktrace : Bool
251241
252242 public init ( logger: Logger = Logger ( label: " Lifeycle " ) ,
253243 callbackQueue: DispatchQueue = . global( ) ,
254- shutdownSignal: [ Lifecycle . Signal ] ? = [ . TERM, . INT] ,
244+ shutdownSignal: [ Signal ] ? = [ . TERM, . INT] ,
255245 installBacktrace: Bool = true ) {
256246 self . logger = logger
257247 self . callbackQueue = callbackQueue
@@ -261,18 +251,22 @@ extension ServiceLifecycle {
261251 }
262252}
263253
254+ struct ShutdownError : Error {
255+ public let errors : [ String : Error ]
256+ }
257+
264258// MARK: - ComponentLifecycle
265259
266260/// `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 {
268262 public let label : String
269263 private let logger : Logger
270264 internal let shutdownGroup = DispatchGroup ( )
271265
272266 private var state = State . idle
273267 private let stateLock = Lock ( )
274268
275- private var tasks = [ Lifecycle . Task ] ( )
269+ private var tasks = [ LifecycleTask ] ( )
276270 private let tasksLock = Lock ( )
277271
278272 /// Creates a `ComponentLifecycle` instance.
@@ -369,7 +363,7 @@ public class ComponentLifecycle: Lifecycle.Task {
369363
370364 // MARK: - private
371365
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 ) {
373367 precondition ( tasks. count > 0 , " invalid number of tasks, must be > 0 " )
374368 self . stateLock. withLock {
375369 guard case . idle = self . state else {
@@ -402,7 +396,7 @@ public class ComponentLifecycle: Lifecycle.Task {
402396 }
403397 }
404398
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 ) {
406400 // async barrier
407401 let start = { ( callback) -> Void in queue. async { tasks [ index] . start ( callback) } }
408402 let callback = { ( index, error) -> Void in queue. async { callback ( index, error) } }
@@ -424,7 +418,7 @@ public class ComponentLifecycle: Lifecycle.Task {
424418 }
425419 }
426420
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 ) {
428422 self . stateLock. withLock {
429423 log ( " shutting down " )
430424 self . state = . shuttingDown( queue)
@@ -441,7 +435,7 @@ public class ComponentLifecycle: Lifecycle.Task {
441435 }
442436 }
443437
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 ) {
445439 // async barrier
446440 let shutdown = { ( callback) -> Void in queue. async { tasks [ index] . shutdown ( callback) } }
447441 let callback = { ( errors) -> Void in queue. async { callback ( errors) } }
@@ -470,17 +464,17 @@ public class ComponentLifecycle: Lifecycle.Task {
470464 private enum State {
471465 case idle
472466 case starting( DispatchQueue )
473- case started( DispatchQueue , [ Lifecycle . Task ] )
467+ case started( DispatchQueue , [ LifecycleTask ] )
474468 case shuttingDown( DispatchQueue )
475469 case shutdown( [ String : Error ] ? )
476470 }
477471}
478472
479473public extension ComponentLifecycle {
480- internal struct Task : Lifecycle . Task {
474+ internal struct Task : LifecycleTask {
481475 let label : String
482- let start : Lifecycle . Handler
483- let shutdown : Lifecycle . Handler
476+ let start : LifecycleHandler
477+ let shutdown : LifecycleHandler
484478
485479 func start( _ callback: @escaping ( Error ? ) -> Void ) {
486480 self . start. run ( callback)
@@ -495,15 +489,15 @@ public extension ComponentLifecycle {
495489 ///
496490 /// - parameters:
497491 /// - tasks: one or more `Tasks`.
498- func register( _ tasks: Lifecycle . Task ... ) {
492+ func register( _ tasks: LifecycleTask ... ) {
499493 self . register ( tasks)
500494 }
501495
502496 /// Adds a `Task` to a `Tasks` collection.
503497 ///
504498 /// - parameters:
505499 /// - tasks: array of `Tasks`.
506- func register( _ tasks: [ Lifecycle . Task ] ) {
500+ func register( _ tasks: [ LifecycleTask ] ) {
507501 self . stateLock. withLock {
508502 guard case . idle = self . state else {
509503 preconditionFailure ( " invalid state, \( self . state) " )
@@ -520,7 +514,7 @@ public extension ComponentLifecycle {
520514 /// - label: label of the item, useful for debugging.
521515 /// - start: `Handler` to perform the startup.
522516 /// - 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 ) {
524518 self . register ( Task ( label: label, start: start, shutdown: shutdown) )
525519 }
526520
@@ -529,7 +523,7 @@ public extension ComponentLifecycle {
529523 /// - parameters:
530524 /// - label: label of the item, useful for debugging.
531525 /// - handler: `Handler` to perform the shutdown.
532- func registerShutdown( label: String , _ handler: Lifecycle . Handler ) {
526+ func registerShutdown( label: String , _ handler: LifecycleHandler ) {
533527 self . register ( label: label, start: . none, shutdown: handler)
534528 }
535529
0 commit comments