Skip to content

Commit

Permalink
Add own version of EventLoopGroupProvider (#241)
Browse files Browse the repository at this point in the history
* Add own version of EventLoopGroupProvider

This version includes .shared or .singleton. Does not include .createNew. Deprecate usage of NIO version

* Add test for singleton EventLoopGroupProvider
  • Loading branch information
adam-fowler authored Oct 6, 2023
1 parent a02f92f commit 0adb5e6
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 5 deletions.
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ let package = Package(
.package(url: "https://github.com/apple/swift-log.git", from: "1.4.0"),
.package(url: "https://github.com/apple/swift-metrics.git", "1.0.0"..<"3.0.0"),
.package(url: "https://github.com/apple/swift-distributed-tracing.git", from: "1.0.1"),
.package(url: "https://github.com/apple/swift-nio.git", from: "2.56.0"),
.package(url: "https://github.com/apple/swift-nio.git", from: "2.58.0"),
.package(url: "https://github.com/swift-server/swift-service-lifecycle.git", from: "1.0.0-alpha.9"),
.package(url: "https://github.com/hummingbird-project/hummingbird-core.git", from: "1.2.1"),
],
Expand Down
48 changes: 44 additions & 4 deletions Sources/Hummingbird/Application.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,25 @@ import NIOTransportServices
/// ```
/// Editing the application setup after calling `start` will produce undefined behaviour.
public final class HBApplication: HBExtensible {
/// Indicates where we should get our EventLoopGroup from
public struct EventLoopGroupProvider {
enum Internal {
case createNew
case shared(EventLoopGroup)
case singleton
}

let value: Internal
init(_ value: Internal) {
self.value = value
}

/// Use EventLoopGroup provided
public static func shared(_ eventLoopGroup: EventLoopGroup) -> Self { .init(.shared(eventLoopGroup)) }
/// Use singleton EventLoopGroup
public static var singleton: Self { .init(.singleton) }
}

// MARK: Member variables

/// server lifecycle, controls initialization and shutdown of application
Expand All @@ -60,14 +79,14 @@ public final class HBApplication: HBExtensible {
public var decoder: HBRequestDecoder

/// who provided the eventLoopGroup
let eventLoopGroupProvider: NIOEventLoopGroupProvider
let eventLoopGroupProvider: HBApplication.EventLoopGroupProvider

// MARK: Initialization

/// Initialize new Application
public init(
configuration: HBApplication.Configuration = HBApplication.Configuration(),
eventLoopGroupProvider: NIOEventLoopGroupProvider = .createNew,
eventLoopGroupProvider: EventLoopGroupProvider = .singleton,
serviceLifecycleProvider: ServiceLifecycleProvider = .createNew
) {
var logger = Logger(label: configuration.serverName ?? "HummingBird")
Expand All @@ -82,13 +101,19 @@ public final class HBApplication: HBExtensible {

// create eventLoopGroup
self.eventLoopGroupProvider = eventLoopGroupProvider
switch eventLoopGroupProvider {
switch self.eventLoopGroupProvider.value {
case .createNew:
#if os(iOS)
self.eventLoopGroup = NIOTSEventLoopGroup()
#else
self.eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
#endif
case .singleton:
#if os(iOS)
self.eventLoopGroup = NIOTSEventLoopGroup.singleton
#else
self.eventLoopGroup = MultiThreadedEventLoopGroup.singleton
#endif
case .shared(let elg):
self.eventLoopGroup = elg
}
Expand Down Expand Up @@ -132,6 +157,21 @@ public final class HBApplication: HBExtensible {
}
}

@available(*, deprecated, message: "Calling HBApplication.init(eventLoopGroupProvider: .createNew) has been deprecated. Use .singleton instead.")
@_disfavoredOverload
public convenience init(
configuration: HBApplication.Configuration = HBApplication.Configuration(),
eventLoopGroupProvider: NIOEventLoopGroupProvider = .createNew,
serviceLifecycleProvider: ServiceLifecycleProvider = .createNew
) {
switch eventLoopGroupProvider {
case .createNew:
self.init(configuration: configuration, eventLoopGroupProvider: .init(.createNew), serviceLifecycleProvider: serviceLifecycleProvider)
case .shared(let elg):
self.init(configuration: configuration, eventLoopGroupProvider: .init(.shared(elg)), serviceLifecycleProvider: serviceLifecycleProvider)
}
}

// MARK: Methods

/// Run application
Expand Down Expand Up @@ -174,7 +214,7 @@ public final class HBApplication: HBExtensible {
public func shutdownApplication() throws {
try self.extensions.shutdown()
try self.threadPool.syncShutdownGracefully()
if case .createNew = self.eventLoopGroupProvider {
if case .createNew = self.eventLoopGroupProvider.value {
try self.eventLoopGroup.syncShutdownGracefully()
}
}
Expand Down
25 changes: 25 additions & 0 deletions Tests/HummingbirdTests/ApplicationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//

import Hummingbird
import HummingbirdCoreXCT
import HummingbirdXCT
import NIOHTTP1
import XCTest
Expand Down Expand Up @@ -473,4 +474,28 @@ final class ApplicationTests: XCTestCase {
XCTAssert(address == "127.0.0.1" || address == "::1")
}
}

func testSingleEventLoopGroup() throws {
let app = HBApplication(eventLoopGroupProvider: .singleton)
app.router.get("/hello") { request -> EventLoopFuture<ByteBuffer> in
let buffer = request.allocator.buffer(string: "GET: Hello")
return request.eventLoop.makeSucceededFuture(buffer)
}
try app.start()
defer { app.stop() }

let client = HBXCTClient(
host: "localhost",
port: app.server.port!,
configuration: .init(timeout: .seconds(15)),
eventLoopGroupProvider: .createNew
)
defer { try? client.syncShutdown() }
client.connect()
let response = try client.get("/hello").wait()
var body = try XCTUnwrap(response.body)
let string = body.readString(length: body.readableBytes)
XCTAssertEqual(response.status, .ok)
XCTAssertEqual(string, "GET: Hello")
}
}

0 comments on commit 0adb5e6

Please sign in to comment.