Repository: apple/swift-nio
File: Sources/NIOTCPEchoClient/Client.swift (Swift)

Code before:
//
//===----------------------------------------------------------------------===//
#if swift(>=5.9)
@_spi(AsyncChannel) import NIOCore
@_spi(AsyncChannel) import NIOPosix

@available(macOS 14, *)
@main
struct Client {
    /// The host to connect to.
    private let host: String
    /// The port to connect to.
    private let port: Int
    /// The client's event loop group.
    private let eventLoopGroup: any EventLoopGroup

    static func main() async throws {
        // We are creating this event loop group at the top level and it will live until
        // the process exits. This means we also don't have to shut it down.
        //
        // Note that we start this group with 1 thread. In general, most NIO programs
        // should use 1 thread as a default unless they're planning to be a network
        // proxy or something that is expecting to be dominated by packet parsing. Most
        // servers aren't, and NIO is very fast, so 1 NIO thread is quite capable of
        // saturating the average small to medium sized machine.
        let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)

        let server = Client(
            host: "localhost",
            port: 8765,
            eventLoopGroup: eventLoopGroup
        )
        try await server.run()

        print("Done sending requests; exiting in 5 seconds")
        try await Task.sleep(for: .seconds(5))
    }

    /// This method starts the server and handles incoming connections.
    func run() async throws {
        try await withThrowingTaskGroup(of: Void.self) { group in
            for i in 0...20 {
                group.addTask {
                    try await self.sendRequest(number: i)
                }
            }

            try await group.waitForAll()
        }
    }


Review comment (suggestion):
Sure, in this case you don't have to shut it down but why leak stuff if it's trivial to not leak?

`defer { try! elg.syncShutdownGracefully() }`

Code after:
//
//===----------------------------------------------------------------------===//
#if swift(>=5.9)
@_spi(AsyncChannel) import NIOCore
@_spi(AsyncChannel) import NIOPosix

@available(macOS 14, *)
@main
struct Client {
    /// The host to connect to.
    private let host: String
    /// The port to connect to.
    private let port: Int
    /// The client's event loop group.
    private let eventLoopGroup: MultiThreadedEventLoopGroup

    static func main() async throws {
        let client = Client(
            host: "localhost",
            port: 8765,
            eventLoopGroup: .singleton
        )
        try await client.run()
    }

    /// This method sends a bunch of requests.
    func run() async throws {
        try await withThrowingTaskGroup(of: Void.self) { group in
            for i in 0...20 {
                group.addTask {
                    try await self.sendRequest(number: i)
                }
            }

            try await group.waitForAll()
        }
    }

    private func sendRequest(number: Int) async throws {
        let channel = try await ClientBootstrap(group: self.eventLoopGroup)
            .connect(
                host: self.host,
                port: self.port
            ) { channel in
                channel.eventLoop.makeCompletedFuture {
                    // We are using two simple handlers here to frame our messages with "\n"
                    try channel.pipeline.syncOperations.addHandler(ByteToMessageHandler(NewlineDelimiterCoder()))
                    try channel.pipeline.syncOperations.addHandler(MessageToByteHandler(NewlineDelimiterCoder()))

                    return try NIOAsyncChannel(
                        synchronouslyWrapping: channel,