Skip to content

Commit 9f5bd6c

Browse files
committed
nested lifecycles
motivation: add ability to create a hirearchy of lifecycles to help manage more complex systems changes: * define top-level lifcycle where signal handling and backtraces are handled * conform Lifecycle to LifecycleItem so that lifecycles can be nested * change shutdown to return an error to better conform with LifecycleItem api
1 parent e15aacc commit 9f5bd6c

File tree

8 files changed

+484
-304
lines changed

8 files changed

+484
-304
lines changed

Sources/ServiceLauncher/Lifecycle.swift

Lines changed: 185 additions & 85 deletions
Large diffs are not rendered by default.

Sources/ServiceLauncherNIOCompat/Bridge.swift

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ extension Lifecycle.Handler {
2121
/// - parameters:
2222
/// - future: the underlying `EventLoopFuture`
2323
public static func eventLoopFuture(_ future: @escaping () -> EventLoopFuture<Void>) -> Lifecycle.Handler {
24-
return Lifecycle.Handler { callback in
24+
return Lifecycle.Handler { queue, callback in
2525
future().whenComplete { result in
26-
switch result {
27-
case .success:
28-
callback(nil)
29-
case .failure(let error):
30-
callback(error)
26+
queue.async {
27+
switch result {
28+
case .success:
29+
callback(nil)
30+
case .failure(let error):
31+
callback(error)
32+
}
3133
}
3234
}
3335
}

Tests/LinuxMain.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import XCTest
2626
@testable import ServiceLauncherTests
2727

2828
XCTMain([
29-
testCase(Tests.allTests),
29+
testCase(LifeycleTests.allTests),
30+
testCase(TopLevelTests.allTests),
3031
])
3132
#endif
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftServiceLauncher open source project
4+
//
5+
// Copyright (c) 2019-2020 Apple Inc. and the SwiftServiceLauncher project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of SwiftServiceLauncher project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import Foundation
16+
import NIO
17+
import NIOConcurrencyHelpers
18+
import ServiceLauncher
19+
20+
class GoodItem: LifecycleItem {
21+
let id: String
22+
let startDelay: Double
23+
let shutdownDelay: Double
24+
25+
var state = State.idle
26+
let stateLock = Lock()
27+
28+
init(id: String = UUID().uuidString,
29+
startDelay: Double = Double.random(in: 0.01 ... 0.1),
30+
shutdownDelay: Double = Double.random(in: 0.01 ... 0.1)) {
31+
self.id = id
32+
self.startDelay = startDelay
33+
self.shutdownDelay = shutdownDelay
34+
}
35+
36+
var label: String {
37+
return self.id
38+
}
39+
40+
func start(on queue: DispatchQueue, callback: @escaping (Error?) -> Void) {
41+
queue.asyncAfter(deadline: .now() + self.startDelay) {
42+
self.stateLock.withLock { self.state = .started }
43+
callback(nil)
44+
}
45+
}
46+
47+
func shutdown(on queue: DispatchQueue, callback: @escaping (Error?) -> Void) {
48+
queue.asyncAfter(deadline: .now() + self.shutdownDelay) {
49+
self.stateLock.withLock { self.state = .shutdown }
50+
callback(nil)
51+
}
52+
}
53+
54+
enum State {
55+
case idle
56+
case started
57+
case shutdown
58+
}
59+
}
60+
61+
class NIOItem {
62+
let id: String
63+
let eventLoopGroup: EventLoopGroup
64+
let startDelay: Int64
65+
let shutdownDelay: Int64
66+
67+
var state = State.idle
68+
let stateLock = Lock()
69+
70+
init(eventLoopGroup: EventLoopGroup,
71+
id: String = UUID().uuidString,
72+
startDelay: Int64 = Int64.random(in: 10 ... 20),
73+
shutdownDelay: Int64 = Int64.random(in: 10 ... 20)) {
74+
self.id = id
75+
self.eventLoopGroup = eventLoopGroup
76+
self.startDelay = startDelay
77+
self.shutdownDelay = shutdownDelay
78+
}
79+
80+
func start() -> EventLoopFuture<Void> {
81+
return self.eventLoopGroup.next().scheduleTask(in: .milliseconds(self.startDelay)) {
82+
self.stateLock.withLock { self.state = .started }
83+
}.futureResult
84+
}
85+
86+
func shutdown() -> EventLoopFuture<Void> {
87+
return self.eventLoopGroup.next().scheduleTask(in: .milliseconds(self.shutdownDelay)) {
88+
self.stateLock.withLock { self.state = .shutdown }
89+
}.futureResult
90+
}
91+
92+
enum State {
93+
case idle
94+
case started
95+
case shutdown
96+
}
97+
}
98+
99+
struct TestError: Error {}

Tests/ServiceLauncherTests/LifecycleTests+XCTest.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,13 @@ import XCTest
2222
/// Do NOT edit this file directly as it will be regenerated automatically when needed.
2323
///
2424

25-
extension Tests {
26-
static var allTests: [(String, (Tests) -> () throws -> Void)] {
25+
extension LifeycleTests {
26+
static var allTests: [(String, (LifeycleTests) -> () throws -> Void)] {
2727
return [
2828
("testStartThenShutdown", testStartThenShutdown),
2929
("testImmediateShutdown", testImmediateShutdown),
3030
("testBadStartup", testBadStartup),
3131
("testBadShutdown", testBadShutdown),
32-
("testStartAndWait", testStartAndWait),
33-
("testBadStartAndWait", testBadStartAndWait),
3432
("testShutdownInOrder", testShutdownInOrder),
3533
("testSync", testSync),
3634
("testAyncBarrier", testAyncBarrier),

0 commit comments

Comments
 (0)