vapor/vapor

Async functions in Xcode 14.3 are bugged

kelvinlauKL opened this issue ยท 8 comments

Describe the bug

Routes that use async functions fail to return responses:

import Vapor

@main
public struct Server {
  public static func main() async throws {
    let app = Application()

    app.get("greet") { req in return "Hello" } // <- closure based route handlers work fine

    app.get("bye", use: bye) // <- route handlers that uses async functions will not return a response
    try app.run()
  }
  
  public static func bye(request: Request) async throws -> String {
    return "bye"
  }
}
// works fine
curl http://127.0.0.1/greet  

// never returns any content
curl http://127.0.0.1/bye

To Reproduce

  1. Create new Swift package named MyServer with Xcode 14.3
  2. Update Package.swift to the following:
// swift-tools-version: 5.8
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "MyServer",
    platforms: [.macOS(.v13)],
    products: [
        .executable(
            name: "MyServer",
            targets: ["MyServer"]),
    ],
    dependencies: [
        .package(url: "https://github.com/vapor/vapor.git", .upToNextMajor(from: "4.0.0"))
    ],
    targets: [
        .executableTarget(
            name: "MyServer",
            dependencies: [
                .product(name: "Vapor", package: "Vapor")
            ]),
        .testTarget(
            name: "MyServerTests",
            dependencies: ["MyServer"]),
    ]
)
  1. In the auto-created MyServer.swift file within Sources/MyServer, add the following code:
import Vapor

@main
public struct Server {
  public static func main() async throws {
    let app = Application()

    app.get("greet") { req in return "Hello" } // <- closure based route handlers work fine

    app.get("bye", use: bye) // <- route handlers that uses async functions will not return a response
    try app.run()
  }
  
  public static func bye(request: Request) async throws -> String {
    return "bye"
  }
}
  1. Run the server by hitting CMD+R on Xcode
  2. Open Terminal and execute the following two commands:
curl http://127.0.0.1:8080/greet
curl http://127.0.0.1:8080/bye

The first curl returns "Hello".

The second curl hangs on Terminal.

  1. Open up the package and run the server on Xcode 14.2

Running the same two curl commands should work fine.

Environment

  • Vapor Framework version: 4.75.0
  • Vapor Toolbox version: n/a
  • OS version: Ventura 13.3

Additional context

I terminated the second curl by ctrl + c. I then ran lsof -i :8080 which yielded the following output:

MyServer 11081 kelvinlau 14u IPv4 <...> 0t0 TCP localhost:http-alt (LISTEN)
MyServer 11081 kelvinlau 15u IPv4 <...> 0t0 TCP localhost:http-alt->localhost:49323 (CLOSE_WAIT)
vzsg commented

If you don't block the main thread inside the @main function by replacing try app.run() with the following snippet, it will start working even with Xcode 14.3.

try app.start()
try await app.running?.onStop.get()

The problem, most likely, is that your main() is marked async. This is a blocking run function (see #2938).

Note that even if this wasn't causing problems on macOS now, this would've caused you headaches on single-core Linux machines still.

Got it. FYI this code was derived from the 2022 WWDC server side swift video, so I expect others to run into this issue too.
Screenshot 2023-04-05 at 11 11 42 AM

Got it. FYI this code was derived from the 2022 WWDC server side swift video, so I expect others to run into this issue too.
Screenshot 2023-04-05 at 11 11 42 AM

just ran into this issue ๐Ÿ˜…

0xTim commented

See the current template's entrypoint for how to configure it correctly until we add an async version on run()

See the current template's entrypoint for how to configure it correctly until we add an async version on run()

Thank you. I found a workaround.

Closing this as this is fixed with the new entry point