Skip to content

Commit 816a92f

Browse files
committed
Rename to ServiceGroup
1 parent 5c49a35 commit 816a92f

9 files changed

+119
-118
lines changed

Sources/ServiceLifecycle/Docs.docc/How to adopt ServiceLifecycle in applications.md

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# How to adopt ServiceLifecycle in applications
22

33
``ServiceLifecycle`` aims to provide a unified API that services should adopt to make orchestrating
4-
them in an application easier. To achieve this ``ServiceLifecycle`` is providing the ``ServiceRunner`` actor.
4+
them in an application easier. To achieve this ``ServiceLifecycle`` is providing the ``ServiceGroup`` actor.
55

66
## Why do we need this?
77

@@ -16,25 +16,25 @@ Swift introduced Structured Concurrency which already helps tremendously with ru
1616
async services concurrently. This can be achieved with the use of task groups. However, Structured
1717
Concurrency doesn't enforce consistent interfaces between the services, so it becomes hard to orchestrate them.
1818
This is where ``ServiceLifecycle`` comes in. It provides the ``Service`` protocol which enforces
19-
a common API. Additionally, it provides the ``ServiceRunner`` which is responsible for orchestrating
19+
a common API. Additionally, it provides the ``ServiceGroup`` which is responsible for orchestrating
2020
all services in an application.
2121

22-
## Adopting the ServiceRunner in your application
22+
## Adopting the ServiceGroup in your application
2323

24-
This article is focusing on how the ``ServiceRunner`` works and how you can adopt it in your application.
24+
This article is focusing on how the ``ServiceGroup`` works and how you can adopt it in your application.
2525
If you are interested in how to properly implement a service, go check out the article: <doc:How-to-adopt-ServiceLifecycle-in-libraries>.
2626

27-
### How is the ServiceRunner working?
27+
### How is the ServiceGroup working?
2828

29-
The ``ServiceRunner`` is just a slightly complicated task group under the hood that runs each service
30-
in a separate child task. Furthermore, the ``ServiceRunner`` handles individual services exiting
29+
The ``ServiceGroup`` is just a slightly complicated task group under the hood that runs each service
30+
in a separate child task. Furthermore, the ``ServiceGroup`` handles individual services exiting
3131
or throwing unexpectedly. Lastly, it also introduces a concept called graceful shutdown which allows
3232
tearing down all services in reverse order safely. Graceful shutdown is often used in server
3333
scenarios i.e. when rolling out a new version and draining traffic from the old version.
3434

35-
### How to use the ServiceRunner?
35+
### How to use the ServiceGroup?
3636

37-
Let's take a look how the ``ServiceRunner`` can be used in an application. First, we define some
37+
Let's take a look how the ``ServiceGroup`` can be used in an application. First, we define some
3838
fictional services.
3939

4040
```swift
@@ -54,8 +54,8 @@ public struct BarService: Service {
5454
```
5555

5656
The `BarService` is depending in our example on the `FooService`. A dependency between services
57-
is quite common and the ``ServiceRunner`` is inferring the dependencies from the order of the
58-
services passed to the ``ServiceRunner/init(services:configuration:logger:)``. Services with a higher
57+
is quite common and the ``ServiceGroup`` is inferring the dependencies from the order of the
58+
services passed to the ``ServiceGroup/init(services:configuration:logger:)``. Services with a higher
5959
index can depend on services with a lower index. The following example shows how this can be applied
6060
to our `BarService`.
6161

@@ -66,25 +66,25 @@ struct Application {
6666
let fooService = FooServer()
6767
let barService = BarService(fooService: fooService)
6868

69-
let serviceRunner = ServiceRunner(
69+
let serviceGroup = ServiceGroup(
7070
// We are encoding the dependency hierarchy here by listing the fooService first
7171
services: [fooService, barService],
7272
configuration: .init(gracefulShutdownSignals: []),
7373
logger: logger
7474
)
7575

76-
try await serviceRunner.run()
76+
try await serviceGroup.run()
7777
}
7878
}
7979
```
8080

8181
### Graceful shutdown
8282

83-
The ``ServiceRunner`` supports graceful shutdown by taking an array of `UnixSignal`s that trigger
83+
The ``ServiceGroup`` supports graceful shutdown by taking an array of `UnixSignal`s that trigger
8484
the shutdown. Commonly `SIGTERM` is used to indicate graceful shutdowns in container environments
85-
such as Docker or Kubernetes. The ``ServiceRunner`` is then gracefully shutting down each service
85+
such as Docker or Kubernetes. The ``ServiceGroup`` is then gracefully shutting down each service
8686
one by one in the reverse order of the array passed to the init.
87-
Importantly, the ``ServiceRunner`` is going to wait for the ``Service/run()`` method to return
87+
Importantly, the ``ServiceGroup`` is going to wait for the ``Service/run()`` method to return
8888
before triggering the graceful shutdown on the next service.
8989

9090
Since graceful shutdown is up to the individual services and application it requires explicit support.
@@ -125,13 +125,13 @@ struct Application {
125125
}
126126
})
127127

128-
let serviceRunner = ServiceRunner(
128+
let serviceGroup = ServiceGroup(
129129
services: [streamingService],
130130
configuration: .init(gracefulShutdownSignals: [.sigterm]),
131131
logger: logger
132132
)
133133

134-
try await serviceRunner.run()
134+
try await serviceGroup.run()
135135
}
136136
}
137137
```
@@ -182,13 +182,13 @@ struct Application {
182182
}
183183
})
184184

185-
let serviceRunner = ServiceRunner(
185+
let serviceGroup = ServiceGroup(
186186
services: [streamingService],
187187
configuration: .init(gracefulShutdownSignals: [.sigterm]),
188188
logger: logger
189189
)
190190

191-
try await serviceRunner.run()
191+
try await serviceGroup.run()
192192
}
193193
}
194194
```

Sources/ServiceLifecycle/Docs.docc/How to adopt ServiceLifecycle in libraries.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,13 @@ public actor TCPEchoClient: Service {
7878
### Returning from your `run()` method
7979

8080
Since the `run()` method contains long running work, returning from it is seen as a failure and will
81-
lead to the ``ServiceRunner`` cancelling all other services by cancelling the task that is running
81+
lead to the ``ServiceGroup`` cancelling all other services by cancelling the task that is running
8282
their respective `run()` method.
8383

8484
### Cancellation
8585

8686
Structured Concurrency propagates task cancellation down the task tree. Every task in the tree can
87-
check for cancellation or react to it with cancellation handlers. The ``ServiceRunner`` is using task
87+
check for cancellation or react to it with cancellation handlers. The ``ServiceGroup`` is using task
8888
cancellation to tear everything down in the case of an early return or thrown error from the `run()`
8989
method of any of the services. Hence it is important that each service properly implements task
9090
cancellation in their `run()` methods.

Sources/ServiceLifecycle/Docs.docc/index.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Applications often have to orchestrate multiple internal services such as
88
clients or servers to implement their business logic. Doing this can become
99
tedious; especially when the APIs of the various services are not interoping nicely
1010
with each other. This library tries to solve this issue by providing a ``Service`` protocol
11-
that services should implement and an orchestrator, the ``ServiceRunner``, that handles
11+
that services should implement and an orchestrator, the ``ServiceGroup``, that handles
1212
running the various services.
1313

1414
This library is fully based on Swift Structured Concurrency which allows it to
@@ -20,7 +20,7 @@ to their business logic if and how to do that.
2020

2121
``ServiceLifecycle`` should be used by both library and application authors to create a seamless experience.
2222
Library authors should conform their services to the ``Service`` protocol and application authors
23-
should use the ``ServiceRunner`` to orchestrate all their services.
23+
should use the ``ServiceGroup`` to orchestrate all their services.
2424

2525
## Topics
2626

@@ -33,15 +33,16 @@ should use the ``ServiceRunner`` to orchestrate all their services.
3333

3434
- ``Service``
3535

36-
### Service Runner
36+
### Service Group
3737

38-
- ``ServiceRunner``
39-
- ``ServiceRunnerConfiguration``
38+
- ``ServiceGroup``
39+
- ``ServiceGroupConfiguration``
4040

4141
### Graceful Shutdown
4242

4343
- ``withGracefulShutdownHandler(operation:onGracefulShutdown:)``
44+
- ``cancelOnGracefulShutdown(_:)``
4445

4546
### Errors
4647

47-
- ``ServiceRunnerError``
48+
- ``ServiceGroupError``

Sources/ServiceLifecycle/GracefulShutdown.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import ConcurrencyHelpers
2525
/// A common use-case is to listen to graceful shutdown and use the `ServerQuiescingHelper` from `swift-nio-extras` to
2626
/// trigger the quiescing sequence. Furthermore, graceful shutdown will propagate to any child task that is currently executing
2727
///
28-
/// - Important: This method will only set up a handler if run inside ``ServiceRunner`` otherwise no graceful shutdown handler
28+
/// - Important: This method will only set up a handler if run inside ``ServiceGroup`` otherwise no graceful shutdown handler
2929
/// will be set up.
3030
///
3131
/// - Parameters:

Sources/ServiceLifecycle/Service.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414

1515
/// This is the basic protocol that a service has to implement.
1616
public protocol Service: Sendable {
17-
/// This method is called when the ``ServiceRunner`` is starting all the services.
17+
/// This method is called when the ``ServiceGroup`` is starting all the services.
1818
///
1919
/// Concrete implementation should execute their long running work in this method such as:
2020
/// - Handling incoming connections and requests
2121
/// - Background refreshes
2222
///
23-
/// - Important: Returning or throwing from this method is indicating a failure of the service and will cause the ``ServiceRunner``
23+
/// - Important: Returning or throwing from this method is indicating a failure of the service and will cause the ``ServiceGroup``
2424
/// to cancel the child tasks of all other running services.
2525
func run() async throws
2626
}

Sources/ServiceLifecycle/ServiceRunner.swift renamed to Sources/ServiceLifecycle/ServiceGroup.swift

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,39 @@
1515
import Logging
1616
import UnixSignals
1717

18-
/// A ``ServiceRunner`` is responsible for running a number of services, setting up signal handling and signalling graceful shutdown to the services.
19-
public actor ServiceRunner: Sendable {
20-
/// The internal state of the ``ServiceRunner``.
18+
/// A ``ServiceGroup`` is responsible for running a number of services, setting up signal handling and signalling graceful shutdown to the services.
19+
public actor ServiceGroup: Sendable {
20+
/// The internal state of the ``ServiceGroup``.
2121
private enum State {
22-
/// The initial state of the runner.
22+
/// The initial state of the group.
2323
case initial
24-
/// The state once ``ServiceRunner/run()`` has been called.
24+
/// The state once ``ServiceGroup/run()`` has been called.
2525
case running(
2626
gracefulShutdownStreamContinuation: AsyncStream<Void>.Continuation
2727
)
28-
/// The state once ``ServiceRunner/run()`` has finished.
28+
/// The state once ``ServiceGroup/run()`` has finished.
2929
case finished
3030
}
3131

3232
/// The services to run.
3333
private let services: [any Service]
34-
/// The runner's configuration.
35-
private let configuration: ServiceRunnerConfiguration
34+
/// The group's configuration.
35+
private let configuration: ServiceGroupConfiguration
3636
/// The logger.
3737
private let logger: Logger
3838

39-
/// The current state of the runner.
39+
/// The current state of the group.
4040
private var state: State = .initial
4141

42-
/// Initializes a new ``ServiceRunner``.
42+
/// Initializes a new ``ServiceGroup``.
4343
///
4444
/// - Parameters:
4545
/// - services: The services to run.
46-
/// - configuration: The runner's configuration.
46+
/// - configuration: The group's configuration.
4747
/// - logger: The logger.
4848
public init(
4949
services: [any Service],
50-
configuration: ServiceRunnerConfiguration,
50+
configuration: ServiceGroupConfiguration,
5151
logger: Logger
5252
) {
5353
self.services = services
@@ -81,7 +81,7 @@ public actor ServiceRunner: Sendable {
8181

8282
switch self.state {
8383
case .initial, .finished:
84-
fatalError("ServiceRunner is in an invalid state \(self.state)")
84+
fatalError("ServiceGroup is in an invalid state \(self.state)")
8585

8686
case .running:
8787
self.state = .finished
@@ -92,10 +92,10 @@ public actor ServiceRunner: Sendable {
9292
}
9393

9494
case .running:
95-
throw ServiceRunnerError.alreadyRunning(file: file, line: line)
95+
throw ServiceGroupError.alreadyRunning(file: file, line: line)
9696

9797
case .finished:
98-
throw ServiceRunnerError.alreadyFinished(file: file, line: line)
98+
throw ServiceGroupError.alreadyFinished(file: file, line: line)
9999
}
100100
}
101101

@@ -228,7 +228,7 @@ public actor ServiceRunner: Sendable {
228228
)
229229

230230
group.cancelAll()
231-
return .failure(ServiceRunnerError.serviceFinishedUnexpectedly())
231+
return .failure(ServiceGroupError.serviceFinishedUnexpectedly())
232232

233233
case .serviceThrew(let service, _, let error):
234234
// One of the servers threw an error. We have to cancel everything else now.
@@ -339,7 +339,7 @@ public actor ServiceRunner: Sendable {
339339
)
340340

341341
group.cancelAll()
342-
throw ServiceRunnerError.serviceFinishedUnexpectedly()
342+
throw ServiceGroupError.serviceFinishedUnexpectedly()
343343
}
344344

345345
case .serviceThrew(let service, _, let error):

Sources/ServiceLifecycle/ServiceRunnerConfiguration.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414

1515
import UnixSignals
1616

17-
/// The configuration for the ``ServiceRunner``.
18-
public struct ServiceRunnerConfiguration: Hashable, Sendable {
19-
/// The runner's logging configuration.
17+
/// The configuration for the ``ServiceGroup``.
18+
public struct ServiceGroupConfiguration: Hashable, Sendable {
19+
/// The group's logging configuration.
2020
public struct LoggingConfiguration: Hashable, Sendable {
2121
public struct Keys: Hashable, Sendable {
2222
/// The logging key used for logging the unix signal.
@@ -30,24 +30,24 @@ public struct ServiceRunnerConfiguration: Hashable, Sendable {
3030
/// The logging key used for logging an error.
3131
public var errorKey = "error"
3232

33-
/// Initializes a new ``ServiceRunnerConfiguration/LoggingConfiguration/Keys``.
33+
/// Initializes a new ``ServiceGroupConfiguration/LoggingConfiguration/Keys``.
3434
public init() {}
3535
}
3636

3737
/// The keys used for logging.
3838
public var keys = Keys()
3939

40-
/// Initializes a new ``ServiceRunnerConfiguration/LoggingConfiguration``.
40+
/// Initializes a new ``ServiceGroupConfiguration/LoggingConfiguration``.
4141
public init() {}
4242
}
4343

4444
/// The signals that lead to graceful shutdown.
4545
public var gracefulShutdownSignals: [UnixSignal]
4646

47-
/// The runner's logging configuration.
47+
/// The group's logging configuration.
4848
public var logging: LoggingConfiguration
4949

50-
/// Initializes a new ``ServiceRunnerConfiguration``.
50+
/// Initializes a new ``ServiceGroupConfiguration``.
5151
///
5252
/// - Parameter gracefulShutdownSignals: The signals that lead to graceful shutdown.
5353
public init(gracefulShutdownSignals: [UnixSignal]) {

Sources/ServiceLifecycle/ServiceRunnerError.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414

15-
/// Errors thrown by the ``ServiceRunner``.
16-
public struct ServiceRunnerError: Error, Hashable, Sendable {
15+
/// Errors thrown by the ``ServiceGroup``.
16+
public struct ServiceGroupError: Error, Hashable, Sendable {
1717
/// A struct representing the possible error codes.
1818
public struct Code: Hashable, Sendable, CustomStringConvertible {
1919
private enum _Code: Hashable, Sendable {
@@ -31,17 +31,17 @@ public struct ServiceRunnerError: Error, Hashable, Sendable {
3131
public var description: String {
3232
switch self.code {
3333
case .alreadyRunning:
34-
return "The service runner is already running the services."
34+
return "The service group is already running the services."
3535
case .alreadyFinished:
36-
return "The service runner has already finished running the services."
36+
return "The service group has already finished running the services."
3737
case .serviceFinishedUnexpectedly:
3838
return "A service has finished unexpectedly."
3939
}
4040
}
4141

42-
/// Indicates that the service runner is already running.
42+
/// Indicates that the service group is already running.
4343
public static let alreadyRunning = Code(code: .alreadyRunning)
44-
/// Indicates that the service runner has already finished running.
44+
/// Indicates that the service group has already finished running.
4545
public static let alreadyFinished = Code(code: .alreadyFinished)
4646
/// Indicates that a service finished unexpectedly.
4747
public static let serviceFinishedUnexpectedly = Code(code: .serviceFinishedUnexpectedly)
@@ -82,7 +82,7 @@ public struct ServiceRunnerError: Error, Hashable, Sendable {
8282
self.backing = backing
8383
}
8484

85-
/// Indicates that the service runner is already running.
85+
/// Indicates that the service group is already running.
8686
public static func alreadyRunning(file: String = #fileID, line: Int = #line) -> Self {
8787
Self(
8888
.init(
@@ -93,7 +93,7 @@ public struct ServiceRunnerError: Error, Hashable, Sendable {
9393
)
9494
}
9595

96-
/// Indicates that the service runner has already finished running.
96+
/// Indicates that the service group has already finished running.
9797
public static func alreadyFinished(file: String = #fileID, line: Int = #line) -> Self {
9898
Self(
9999
.init(
@@ -116,8 +116,8 @@ public struct ServiceRunnerError: Error, Hashable, Sendable {
116116
}
117117
}
118118

119-
extension ServiceRunnerError: CustomStringConvertible {
119+
extension ServiceGroupError: CustomStringConvertible {
120120
public var description: String {
121-
"ServiceRunnerError: errorCode: \(self.backing.errorCode), file: \(self.backing.file), line: \(self.backing.line)"
121+
"ServiceGroupError: errorCode: \(self.backing.errorCode), file: \(self.backing.file), line: \(self.backing.line)"
122122
}
123123
}

0 commit comments

Comments
 (0)