Skip to content

Commit adfec6a

Browse files
tomerdyim-leektoso
authored
API docs cleanup and other minor fixes (#73)
motivation: better API docs and usability changes: * allow customization of ServiceLifecycle label * adjust APi docs * fix tests on macOS (availability) Co-authored-by: Yim Lee <yim_lee@apple.com> Co-authored-by: Konrad `ktoso` Malawski <konrad.malawski@project13.pl>
1 parent c0c2224 commit adfec6a

File tree

2 files changed

+67
-46
lines changed

2 files changed

+67
-46
lines changed

Sources/Lifecycle/Lifecycle.swift

Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -36,23 +36,23 @@ public protocol LifecycleTask {
3636
public struct LifecycleHandler {
3737
private let body: (@escaping (Error?) -> Void) -> Void
3838

39-
/// Initialize a `Lifecycle.Handler` based on a completion handler.
39+
/// Initialize a `LifecycleHandler` based on a completion handler.
4040
///
4141
/// - parameters:
4242
/// - callback: the underlying completion handler
4343
public init(_ callback: @escaping (@escaping (Error?) -> Void) -> Void) {
4444
self.body = callback
4545
}
4646

47-
/// Asynchronous `Lifecycle.Handler` based on a completion handler.
47+
/// Asynchronous `LifecycleHandler` based on a completion handler.
4848
///
4949
/// - parameters:
5050
/// - callback: the underlying completion handler
5151
public static func async(_ callback: @escaping (@escaping (Error?) -> Void) -> Void) -> LifecycleHandler {
5252
return LifecycleHandler(callback)
5353
}
5454

55-
/// Asynchronous `Lifecycle.Handler` based on a blocking, throwing function.
55+
/// Asynchronous `LifecycleHandler` based on a blocking, throwing function.
5656
///
5757
/// - parameters:
5858
/// - body: the underlying function
@@ -67,7 +67,7 @@ public struct LifecycleHandler {
6767
}
6868
}
6969

70-
/// Noop `Lifecycle.Handler`.
70+
/// Noop `LifecycleHandler`.
7171
public static var none: LifecycleHandler {
7272
return LifecycleHandler { callback in
7373
callback(nil)
@@ -83,65 +83,74 @@ public struct LifecycleHandler {
8383

8484
public struct ServiceLifecycle {
8585
private let configuration: Configuration
86-
private let lifecycle: ComponentLifecycle
8786

88-
/// Creates a `ComponentLifecycle` instance.
87+
/// The underlying `ComponentLifecycle` instance
88+
///
89+
/// Designed for composition purposes, mainly for frameworks that need to offer both top-level start/stop functionality and composition into larger systems.
90+
/// In other words, should not be used outside the context of building an Application framework.
91+
private let underlying: ComponentLifecycle
92+
93+
/// Creates a `ServiceLifecycle` instance.
8994
///
9095
/// - parameters:
9196
/// - configuration: Defines lifecycle `Configuration`
9297
public init(configuration: Configuration = .init()) {
9398
self.configuration = configuration
94-
self.lifecycle = ComponentLifecycle(label: "Lifecycle", logger: self.configuration.logger)
99+
self.underlying = ComponentLifecycle(label: self.configuration.label, logger: self.configuration.logger)
95100
// setup backtrace trap as soon as possible
96101
if configuration.installBacktrace {
97-
self.lifecycle.log("installing backtrace")
102+
self.log("installing backtrace")
98103
Backtrace.install()
99104
}
100105
}
101106

102-
/// Starts the provided `LifecycleItem` array.
107+
/// Starts the provided `LifecycleTask` array.
103108
/// Startup is performed in the order of items provided.
104109
///
105110
/// - parameters:
106111
/// - callback: The handler which is called after the start operation completes. The parameter will be `nil` on success and contain the `Error` otherwise.
107112
public func start(_ callback: @escaping (Error?) -> Void) {
108113
self.setupShutdownHook()
109-
self.lifecycle.start(on: self.configuration.callbackQueue, callback)
114+
self.underlying.start(on: self.configuration.callbackQueue, callback)
110115
}
111116

112-
/// Starts the provided `LifecycleItem` array and waits (blocking) until a shutdown `Signal` is captured or `shutdown` is called on another thread.
117+
/// Starts the provided `LifecycleTask` array and waits (blocking) until a shutdown `Signal` is captured or `shutdown` is called on another thread.
113118
/// Startup is performed in the order of items provided.
114119
public func startAndWait() throws {
115120
self.setupShutdownHook()
116-
try self.lifecycle.startAndWait(on: self.configuration.callbackQueue)
121+
try self.underlying.startAndWait(on: self.configuration.callbackQueue)
117122
}
118123

119-
/// Shuts down the `LifecycleItem` array provided in `start` or `startAndWait`.
124+
/// Shuts down the `LifecycleTask` array provided in `start` or `startAndWait`.
120125
/// Shutdown is performed in reverse order of items provided.
121126
///
122127
/// - parameters:
123128
/// - callback: The handler which is called after the start operation completes. The parameter will be `nil` on success and contain the `Error` otherwise.
124129
public func shutdown(_ callback: @escaping (Error?) -> Void = { _ in }) {
125-
self.lifecycle.shutdown(callback)
130+
self.underlying.shutdown(callback)
126131
}
127132

128133
/// Waits (blocking) until shutdown `Signal` is captured or `shutdown` is invoked on another thread.
129134
public func wait() {
130-
self.lifecycle.wait()
135+
self.underlying.wait()
131136
}
132137

133138
private func setupShutdownHook() {
134139
self.configuration.shutdownSignal?.forEach { signal in
135-
self.lifecycle.log("setting up shutdown hook on \(signal)")
140+
self.log("setting up shutdown hook on \(signal)")
136141
let signalSource = ServiceLifecycle.trap(signal: signal, handler: { signal in
137-
self.lifecycle.log("intercepted signal: \(signal)")
142+
self.log("intercepted signal: \(signal)")
138143
self.shutdown()
139144
})
140-
self.lifecycle.shutdownGroup.notify(queue: .global()) {
145+
self.underlying.shutdownGroup.notify(queue: .global()) {
141146
signalSource.cancel()
142147
}
143148
}
144149
}
150+
151+
private func log(_ message: String) {
152+
self.underlying.log(message)
153+
}
145154
}
146155

147156
extension ServiceLifecycle {
@@ -186,45 +195,47 @@ extension ServiceLifecycle {
186195
}
187196

188197
public extension ServiceLifecycle {
189-
/// Adds a `Task` to a `Tasks` collection.
198+
/// Adds a `LifecycleTask` to a `LifecycleTasks` collection.
190199
///
191200
/// - parameters:
192-
/// - tasks: one or more `Tasks`.
201+
/// - tasks: one or more `LifecycleTask`.
193202
func register(_ tasks: LifecycleTask ...) {
194-
self.lifecycle.register(tasks)
203+
self.underlying.register(tasks)
195204
}
196205

197-
/// Adds a `Task` to a `Tasks` collection.
206+
/// Adds a `LifecycleTask` to a `LifecycleTasks` collection.
198207
///
199208
/// - parameters:
200-
/// - tasks: array of `Tasks`.
209+
/// - tasks: array of `LifecycleTask`.
201210
func register(_ tasks: [LifecycleTask]) {
202-
self.lifecycle.register(tasks)
211+
self.underlying.register(tasks)
203212
}
204213

205-
/// Adds a `Task` to a `Tasks` collection.
214+
/// Adds a `LifecycleTask` to a `LifecycleTasks` collection.
206215
///
207216
/// - parameters:
208217
/// - label: label of the item, useful for debugging.
209-
/// - start: `Handler` to perform the startup.
210-
/// - shutdown: `Handler` to perform the shutdown.
218+
/// - start: `LifecycleHandler` to perform the startup.
219+
/// - shutdown: `LifecycleHandler` to perform the shutdown.
211220
func register(label: String, start: LifecycleHandler, shutdown: LifecycleHandler) {
212-
self.lifecycle.register(label: label, start: start, shutdown: shutdown)
221+
self.underlying.register(label: label, start: start, shutdown: shutdown)
213222
}
214223

215-
/// Adds a `Task` to a `Tasks` collection.
224+
/// Adds a `LifecycleTask` to a `LifecycleTasks` collection.
216225
///
217226
/// - parameters:
218227
/// - label: label of the item, useful for debugging.
219-
/// - handler: `Handler` to perform the shutdown.
228+
/// - handler: `LifecycleHandler` to perform the shutdown.
220229
func registerShutdown(label: String, _ handler: LifecycleHandler) {
221-
self.lifecycle.registerShutdown(label: label, handler)
230+
self.underlying.registerShutdown(label: label, handler)
222231
}
223232
}
224233

225234
extension ServiceLifecycle {
226-
/// `Lifecycle` configuration options.
235+
/// `ServiceLifecycle` configuration options.
227236
public struct Configuration {
237+
/// Defines the `label` for the lifeycle and its Logger
238+
public var label: String
228239
/// Defines the `Logger` to log with.
229240
public var logger: Logger
230241
/// Defines the `DispatchQueue` on which startup and shutdown callback handlers are run.
@@ -234,11 +245,13 @@ extension ServiceLifecycle {
234245
/// Defines if to install a crash signal trap that prints backtraces.
235246
public var installBacktrace: Bool
236247

237-
public init(logger: Logger = Logger(label: "Lifecycle"),
248+
public init(label: String = "Lifecycle",
249+
logger: Logger? = nil,
238250
callbackQueue: DispatchQueue = .global(),
239251
shutdownSignal: [Signal]? = [.TERM, .INT],
240252
installBacktrace: Bool = true) {
241-
self.logger = logger
253+
self.label = label
254+
self.logger = logger ?? Logger(label: label)
242255
self.callbackQueue = callbackQueue
243256
self.shutdownSignal = shutdownSignal
244257
self.installBacktrace = installBacktrace
@@ -275,7 +288,7 @@ public class ComponentLifecycle: LifecycleTask {
275288
self.shutdownGroup.enter()
276289
}
277290

278-
/// Starts the provided `LifecycleItem` array.
291+
/// Starts the provided `LifecycleTask` array.
279292
/// Startup is performed in the order of items provided.
280293
///
281294
/// - parameters:
@@ -284,7 +297,7 @@ public class ComponentLifecycle: LifecycleTask {
284297
self.start(on: .global(), callback)
285298
}
286299

287-
/// Starts the provided `LifecycleItem` array.
300+
/// Starts the provided `LifecycleTask` array.
288301
/// Startup is performed in the order of items provided.
289302
///
290303
/// - parameters:
@@ -295,7 +308,7 @@ public class ComponentLifecycle: LifecycleTask {
295308
self._start(on: queue, tasks: tasks, callback: callback)
296309
}
297310

298-
/// Starts the provided `LifecycleItem` array and waits (blocking) until `shutdown` is called on another thread.
311+
/// Starts the provided `LifecycleTask` array and waits (blocking) until `shutdown` is called on another thread.
299312
/// Startup is performed in the order of items provided.
300313
///
301314
/// - parameters:
@@ -313,7 +326,7 @@ public class ComponentLifecycle: LifecycleTask {
313326
self.wait()
314327
}
315328

316-
/// Shuts down the `LifecycleItem` array provided in `start` or `startAndWait`.
329+
/// Shuts down the `LifecycleTask` array provided in `start` or `startAndWait`.
317330
/// Shutdown is performed in reverse order of items provided.
318331
public func shutdown(_ callback: @escaping (Error?) -> Void = { _ in }) {
319332
let setupShutdownListener = { (queue: DispatchQueue) in
@@ -482,18 +495,18 @@ public extension ComponentLifecycle {
482495
}
483496
}
484497

485-
/// Adds a `Task` to a `Tasks` collection.
498+
/// Adds a `LifecycleTask` to a `LifecycleTasks` collection.
486499
///
487500
/// - parameters:
488-
/// - tasks: one or more `Tasks`.
501+
/// - tasks: one or more `LifecycleTask`.
489502
func register(_ tasks: LifecycleTask ...) {
490503
self.register(tasks)
491504
}
492505

493-
/// Adds a `Task` to a `Tasks` collection.
506+
/// Adds a `LifecycleTask` to a `LifecycleTasks` collection.
494507
///
495508
/// - parameters:
496-
/// - tasks: array of `Tasks`.
509+
/// - tasks: array of `LifecycleTask`.
497510
func register(_ tasks: [LifecycleTask]) {
498511
self.stateLock.withLock {
499512
guard case .idle = self.state else {
@@ -505,7 +518,7 @@ public extension ComponentLifecycle {
505518
}
506519
}
507520

508-
/// Adds a `Task` to a `Tasks` collection.
521+
/// Adds a `LifecycleTask` to a `LifecycleTasks` collection.
509522
///
510523
/// - parameters:
511524
/// - label: label of the item, useful for debugging.
@@ -515,7 +528,7 @@ public extension ComponentLifecycle {
515528
self.register(Task(label: label, start: start, shutdown: shutdown))
516529
}
517530

518-
/// Adds a `Task` to a `Tasks` collection.
531+
/// Adds a `LifecycleTask` to a `LifecycleTasks` collection.
519532
///
520533
/// - parameters:
521534
/// - label: label of the item, useful for debugging.

Tests/LifecycleTests/ComponentLifecycleTests.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ final class ComponentLifecycleTests: XCTestCase {
3232
items.forEach { XCTAssertEqual($0.state, .shutdown, "expected item to be shutdown, but \($0.state)") }
3333
}
3434

35-
func testDefaultCallbackQueue() {
35+
func testDefaultCallbackQueue() throws {
36+
guard #available(OSX 10.12, *) else {
37+
return
38+
}
39+
3640
let lifecycle = ComponentLifecycle(label: "test")
3741
var startCalls = [String]()
3842
var stopCalls = [String]()
@@ -65,7 +69,11 @@ final class ComponentLifecycleTests: XCTestCase {
6569
items.forEach { item in XCTAssertTrue(stopCalls.contains(item.label), "expected \(item.label) to be stopped") }
6670
}
6771

68-
func testUserDefinedCallbackQueue() {
72+
func testUserDefinedCallbackQueue() throws {
73+
guard #available(OSX 10.12, *) else {
74+
return
75+
}
76+
6977
let lifecycle = ComponentLifecycle(label: "test")
7078
let testQueue = DispatchQueue(label: UUID().uuidString)
7179
var startCalls = [String]()

0 commit comments

Comments
 (0)