Skip to content

[HTTPSchedulableRequest] EventLoop preferences #415

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions Sources/AsyncHTTPClient/ConnectionPool/HTTPConnectionPool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,15 @@ extension HTTPConnectionPool {
}

var requiredEventLoop: EventLoop? {
switch self.req.eventLoopPreference.preference {
case .indifferent, .delegate:
return nil
case .delegateAndChannel(on: let eventLoop), .testOnly_exact(channelOn: let eventLoop, delegateOn: _):
return eventLoop
}
self.req.requiredEventLoop
}

var preferredEventLoop: EventLoop {
self.req.preferredEventLoop
}

var connectionDeadline: NIODeadline? {
self.req.connectionDeadline
}

func __testOnly_wrapped_request() -> HTTPSchedulableRequest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,12 @@ protocol HTTPSchedulableRequest: HTTPExecutableRequest {
/// A connection to run this task on needs to be found before this deadline!
var connectionDeadline: NIODeadline { get }

/// The task's `EventLoop` preference
var eventLoopPreference: HTTPClient.EventLoopPreference { get }
/// The user has expressed an intent for this request to be executed on this EventLoop. If a
/// connection is available on another one, just use the one handy.
var preferredEventLoop: EventLoop { get }

/// The user required the request to be executed on a connection that is handled by this EventLoop.
var requiredEventLoop: EventLoop? { get }

/// Informs the task, that it was queued for execution
///
Expand Down
20 changes: 20 additions & 0 deletions Sources/AsyncHTTPClient/RequestBag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,26 @@ extension RequestBag: HTTPSchedulableRequest {
}

extension RequestBag: HTTPExecutableRequest {
var requiredEventLoop: EventLoop? {
switch self.eventLoopPreference.preference {
case .indifferent, .delegate:
return nil
case .delegateAndChannel(on: let eventLoop), .testOnly_exact(channelOn: let eventLoop, delegateOn: _):
return eventLoop
}
}

var preferredEventLoop: EventLoop {
switch self.eventLoopPreference.preference {
case .indifferent:
return self.task.eventLoop
case .delegate(let eventLoop),
.delegateAndChannel(on: let eventLoop),
.testOnly_exact(channelOn: let eventLoop, delegateOn: _):
return eventLoop
}
}

func willExecuteRequest(_ executor: HTTPRequestExecutor) {
if self.task.eventLoop.inEventLoop {
self.willExecuteRequest0(executor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ class HTTPConnectionPool_RequestQueueTests: XCTestCase {
var queue = HTTPConnectionPool.RequestQueue()
XCTAssertTrue(queue.isEmpty)
XCTAssertEqual(queue.count, 0)
let req1 = MockScheduledRequest(eventLoopPreference: .indifferent)
let req1 = MockScheduledRequest(requiredEventLoop: nil)
let req1ID = queue.push(.init(req1))
XCTAssertFalse(queue.isEmpty)
XCTAssertFalse(queue.isEmpty(for: nil))
XCTAssertEqual(queue.count, 1)
XCTAssertEqual(queue.count(for: nil), 1)

let req2 = MockScheduledRequest(eventLoopPreference: .indifferent)
let req2 = MockScheduledRequest(requiredEventLoop: nil)
let req2ID = queue.push(.init(req2))
XCTAssertEqual(queue.count, 2)

Expand All @@ -47,7 +47,7 @@ class HTTPConnectionPool_RequestQueueTests: XCTestCase {

XCTAssertTrue(queue.isEmpty(for: eventLoop))
XCTAssertEqual(queue.count(for: eventLoop), 0)
let req3 = MockScheduledRequest(eventLoopPreference: .delegateAndChannel(on: eventLoop))
let req3 = MockScheduledRequest(requiredEventLoop: eventLoop)
let req3ID = queue.push(.init(req3))
XCTAssertFalse(queue.isEmpty(for: eventLoop))
XCTAssertEqual(queue.count(for: eventLoop), 1)
Expand All @@ -60,13 +60,13 @@ class HTTPConnectionPool_RequestQueueTests: XCTestCase {
XCTAssertTrue(queue.isEmpty)
XCTAssertEqual(queue.count, 0)

let req4 = MockScheduledRequest(eventLoopPreference: .delegateAndChannel(on: eventLoop))
let req4 = MockScheduledRequest(requiredEventLoop: eventLoop)
let req4ID = queue.push(.init(req4))
XCTAssert(queue.remove(req4ID)?.__testOnly_wrapped_request() === req4)

let req5 = MockScheduledRequest(eventLoopPreference: .indifferent)
let req5 = MockScheduledRequest(requiredEventLoop: nil)
queue.push(.init(req5))
let req6 = MockScheduledRequest(eventLoopPreference: .delegateAndChannel(on: eventLoop))
let req6 = MockScheduledRequest(requiredEventLoop: eventLoop)
queue.push(.init(req6))
let all = queue.removeAll()
let testSet = all.map { $0.__testOnly_wrapped_request() }
Expand All @@ -82,13 +82,15 @@ class HTTPConnectionPool_RequestQueueTests: XCTestCase {
}

private class MockScheduledRequest: HTTPSchedulableRequest {
init(eventLoopPreference: HTTPClient.EventLoopPreference) {
self.eventLoopPreference = eventLoopPreference
let requiredEventLoop: EventLoop?

init(requiredEventLoop: EventLoop?) {
self.requiredEventLoop = requiredEventLoop
}

var logger: Logger { preconditionFailure("Unimplemented") }
var connectionDeadline: NIODeadline { preconditionFailure("Unimplemented") }
let eventLoopPreference: HTTPClient.EventLoopPreference
var preferredEventLoop: EventLoop { preconditionFailure("Unimplemented") }

func requestWasQueued(_: HTTPRequestScheduler) {
preconditionFailure("Unimplemented")
Expand Down