diff --git a/Sources/ServiceLifecycle/Docs.docc/curation/ServiceGroupError.md b/Sources/ServiceLifecycle/Docs.docc/curation/ServiceGroupError.md index a0d523a..7207895 100644 --- a/Sources/ServiceLifecycle/Docs.docc/curation/ServiceGroupError.md +++ b/Sources/ServiceLifecycle/Docs.docc/curation/ServiceGroupError.md @@ -9,6 +9,6 @@ ### Service Group Errors -- ``serviceFinishedUnexpectedly(file:line:)`` +- ``serviceFinishedUnexpectedly(file:line:service:)`` - ``alreadyRunning(file:line:)`` - ``alreadyFinished(file:line:)`` diff --git a/Sources/ServiceLifecycle/ServiceGroup.swift b/Sources/ServiceLifecycle/ServiceGroup.swift index 668eea4..4a61496 100644 --- a/Sources/ServiceLifecycle/ServiceGroup.swift +++ b/Sources/ServiceLifecycle/ServiceGroup.swift @@ -407,7 +407,7 @@ public actor ServiceGroup: Sendable, Service { group: &group, cancellationTimeoutTask: &cancellationTimeoutTask ) - return .failure(ServiceGroupError.serviceFinishedUnexpectedly()) + return .failure(ServiceGroupError.serviceFinishedUnexpectedly(service: "\(service.service)")) case .gracefullyShutdownGroup: self.logger.debug( @@ -670,7 +670,7 @@ public actor ServiceGroup: Sendable, Service { group: &group, cancellationTimeoutTask: &cancellationTimeoutTask ) - throw ServiceGroupError.serviceFinishedUnexpectedly() + throw ServiceGroupError.serviceFinishedUnexpectedly(service: "\(service.service)") } // The service that we signalled graceful shutdown did exit/ // We can continue to the next one. diff --git a/Sources/ServiceLifecycle/ServiceRunnerError.swift b/Sources/ServiceLifecycle/ServiceRunnerError.swift index c937bc8..3df32ec 100644 --- a/Sources/ServiceLifecycle/ServiceRunnerError.swift +++ b/Sources/ServiceLifecycle/ServiceRunnerError.swift @@ -50,14 +50,16 @@ public struct ServiceGroupError: Error, Hashable, Sendable { /// Internal class that contains the actual error code. private final class Backing: Hashable, Sendable { + let message: String? let errorCode: Code let file: String let line: Int - init(errorCode: Code, file: String, line: Int) { + init(errorCode: Code, file: String, line: Int, message: String?) { self.errorCode = errorCode self.file = file self.line = line + self.message = message } static func == (lhs: Backing, rhs: Backing) -> Bool { @@ -83,35 +85,42 @@ public struct ServiceGroupError: Error, Hashable, Sendable { self.backing = backing } - /// An error that indicates that the service group is already running. + /// Indicates that the service group is already running. public static func alreadyRunning(file: String = #fileID, line: Int = #line) -> Self { Self( .init( errorCode: .alreadyRunning, file: file, - line: line + line: line, + message: "" ) ) } - /// An error that indicates that the service group has already finished running. + /// Indicates that the service group has already finished running. public static func alreadyFinished(file: String = #fileID, line: Int = #line) -> Self { Self( .init( errorCode: .alreadyFinished, file: file, - line: line + line: line, + message: "" ) ) } - /// An error that indicates that a service finished unexpectedly even though it indicated it is a long running service. - public static func serviceFinishedUnexpectedly(file: String = #fileID, line: Int = #line) -> Self { + /// Indicates that a service finished unexpectedly even though it indicated it is a long running service. + public static func serviceFinishedUnexpectedly( + file: String = #fileID, + line: Int = #line, + service: String? = nil + ) -> Self { Self( .init( errorCode: .serviceFinishedUnexpectedly, file: file, - line: line + line: line, + message: service.flatMap { "Service failed(\($0))" } ) ) } @@ -120,6 +129,6 @@ public struct ServiceGroupError: Error, Hashable, Sendable { extension ServiceGroupError: CustomStringConvertible { /// A string representation of the service group error. public var description: String { - "ServiceGroupError: errorCode: \(self.backing.errorCode), file: \(self.backing.file), line: \(self.backing.line)" + "ServiceGroupError: errorCode: \(self.backing.errorCode), file: \(self.backing.file), line: \(self.backing.line) \(self.backing.message.flatMap { ", message: \($0)" } ?? "")" } } diff --git a/Tests/ServiceLifecycleTests/ServiceGroupTests.swift b/Tests/ServiceLifecycleTests/ServiceGroupTests.swift index 0120251..a936e9d 100644 --- a/Tests/ServiceLifecycleTests/ServiceGroupTests.swift +++ b/Tests/ServiceLifecycleTests/ServiceGroupTests.swift @@ -122,7 +122,10 @@ final class ServiceGroupTests: XCTestCase { await mockService.resumeRunContinuation(with: .success(())) try await XCTAsyncAssertThrowsError(await group.next()) { - XCTAssertEqual($0 as? ServiceGroupError, .serviceFinishedUnexpectedly()) + XCTAssertEqual( + $0 as? ServiceGroupError, + .serviceFinishedUnexpectedly(service: "Service1") + ) } } } @@ -290,7 +293,10 @@ final class ServiceGroupTests: XCTestCase { await longService.resumeRunContinuation(with: .success(())) try await XCTAsyncAssertThrowsError(await group.next()) { - XCTAssertEqual($0 as? ServiceGroupError, .serviceFinishedUnexpectedly()) + XCTAssertEqual( + $0 as? ServiceGroupError, + .serviceFinishedUnexpectedly(service: "Service1") + ) } } }