Repository: apple/swift-nio
File: Sources/NIOCore/EventLoop.swift (Swift)

Code before:
        let continuation = DispatchWorkItem {}
        self.shutdownGracefully { error in
            if let error = error {
                errorStorageLock.withLock {
                    errorStorage = error
                }
            }
            continuation.perform()
        }
        continuation.wait()
        try errorStorageLock.withLock {
            if let error = errorStorage {
                throw error
            }
        }
    }

    public func _preconditionSafeToSyncShutdown(file: StaticString, line: UInt) {
        return
    }
}

/// This type was intended to be used by libraries which use NIO, and offer their users either the option
/// to `.share` an existing event loop group or create (and manage) a new one (`.createNew`) and let it be
/// managed by given library and its lifecycle.
@available(*, deprecated,
            message: """
                     Please use a `group: any EventLoopGroup` parameter instead. If you want to default to a global
                     singleton group instead, consider
                     `group: any EventLoopGroup = MultiThreadedEventLoopGroup.globalSingleton` or
                     similar. Having the option to `.createNew`
                     EventLoopGroups causes more issues than it solves.
                     See also: https://github.com/apple/swift-nio/issues/2142
                     """)
public enum NIOEventLoopGroupProvider {
    /// Use an `EventLoopGroup` provided by the user.
    /// The owner of this group is responsible for its lifecycle.
    case shared(EventLoopGroup)
    /// Create a new `EventLoopGroup` when necessary.
    /// The library which accepts this provider takes ownership of the created event loop group,
    /// and must ensure its proper shutdown when the library is being shut down.
    case createNew
}

#if swift(>=5.7)
@available(*, deprecated)
extension NIOEventLoopGroupProvider: Sendable {}
#endif

/// Different `Error`s that are specific to `EventLoop` operations / implementations.
public enum EventLoopError: Error {

Review comment (suggestion):
The deprecation path could be a bit painful here as it affects libraries and users. e.g. NIO can deprecate this and users are stuck with warnings until intermediate libraries update their APIs and do a release. Not sure if I'm overthinking this.

We could just deprecate the `createNew` case. End users can provide `.shared(MultiThreadedEventLoopGroup.singleton)` until libraries add new APIs which just take `any EventLoopGroup`. 

Code after:
///
/// Please use a `group: any EventLoopGroup` parameter instead. If you want to default to a global
/// singleton group instead, consider group: any EventLoopGroup = MultiThreadedEventLoopGroup.singleton` or
/// similar.
///
/// - See also: https://github.com/apple/swift-nio/issues/2142
public enum NIOEventLoopGroupProvider {
    /// Use an `EventLoopGroup` provided by the user.
    /// The owner of this group is responsible for its lifecycle.
    case shared(EventLoopGroup)

    /// Deprecated. Create a new `EventLoopGroup` when necessary.
    /// The library which accepts this provider takes ownership of the created event loop group,
    /// and must ensure its proper shutdown when the library is being shut down.
    @available(
        *,
        deprecated,
        message: """
            Please use `.shared(existingGroup)` or use the singleton via \
            `.shared(MultiThreadedEventLoopGroup.singleton)` or similar
            """
    )
    case createNew
}

extension NIOEventLoopGroupProvider: Sendable {}

/// Different `Error`s that are specific to `EventLoop` operations / implementations.
public enum EventLoopError: Error {
    /// An operation was executed that is not supported by the `EventLoop`
    case unsupportedOperation

    /// An scheduled task was cancelled.
    case cancelled

    /// The `EventLoop` was shutdown already.
    case shutdown

    /// Shutting down the `EventLoop` failed.
    case shutdownFailed
}

extension EventLoopError {
    @usableFromInline
    static let _cancelled: any Error = EventLoopError.cancelled
}

extension EventLoopError: CustomStringConvertible {
    public var description: String {
        switch self {
        case .unsupportedOperation: