Skip to content

Tolerate futures from arbitrary event loops #96

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 2 commits into from
Sep 6, 2019
Merged

Tolerate futures from arbitrary event loops #96

merged 2 commits into from
Sep 6, 2019

Conversation

PopFlamingo
Copy link
Contributor

This commit should fix #95 and adds associated tests

@swift-server-bot
Copy link

Can one of the admins verify this patch?

Copy link
Contributor Author

@PopFlamingo PopFlamingo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added multiple review comments to explain the changes and to ensure everything is correct.

@@ -366,15 +366,15 @@ extension HTTPClient {
/// `EventLoopFuture<Response>` of the execution or cancellation of the execution.
public final class Task<Response> {
/// `EventLoop` used to execute and process this request.
public let eventLoop: EventLoop
public internal(set) var currentEventLoop: EventLoop
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that this is a variable, we must not allow mutation from the public scope.
I thought it might be the right time to set it to currentEventLoop as discussed in the recent comments in #82 now that this property is a variable, but I can also make the name change in another commit if preferred.
cc @weissi @artemredkin

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good but we need some synchronisation here because it is mutable might be accessed from different threads now. I'd suggest to depend on NIOConcurrencyHelpers and store it in

private let _currentEventLoop: AtomicBox<EventLoop>
public var currentEventLoop: EventLoop {
    return self._currentEventLoop.load()
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need it to be var? I somehow missed it

Copy link
Contributor Author

@PopFlamingo PopFlamingo Sep 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@artemredkin It's because of setChannel(...): when it updates the channel, it must also update the current event loop at the same time.

@@ -61,23 +61,19 @@ class HTTPClientTests: XCTestCase {
let response = try httpClient.get(url: "http://localhost:\(httpBin.port)/get").wait()
XCTAssertEqual(.ok, response.status)
}

func testGetWithSharedEventLoopGroup() throws {
Copy link
Contributor Author

@PopFlamingo PopFlamingo Aug 31, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be needed anymore now that we take care of the threading issues. This test could be re-introduced when we add a requires event loop preference to check that the requirements are always met.

@PopFlamingo PopFlamingo changed the title Fix #95 Tolerate futures from arbitrary event loops Aug 31, 2019
@artemredkin
Copy link
Collaborator

@swift-server-bot test this please

@artemredkin
Copy link
Collaborator

@adtrevor there are formatting issues, but otherwise looks good, thank you!

Copy link
Contributor

@weissi weissi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! This looks good, added a few comments regarding thread safety.

@@ -366,15 +366,15 @@ extension HTTPClient {
/// `EventLoopFuture<Response>` of the execution or cancellation of the execution.
public final class Task<Response> {
/// `EventLoop` used to execute and process this request.
public let eventLoop: EventLoop
public internal(set) var currentEventLoop: EventLoop
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good but we need some synchronisation here because it is mutable might be accessed from different threads now. I'd suggest to depend on NIOConcurrencyHelpers and store it in

private let _currentEventLoop: AtomicBox<EventLoop>
public var currentEventLoop: EventLoop {
    return self._currentEventLoop.load()
}

@weissi weissi added the ⚠️ semver/major Breaks existing public API. label Sep 1, 2019
@weissi weissi added this to the 1.0.0 milestone Sep 1, 2019
@PopFlamingo
Copy link
Contributor Author

PopFlamingo commented Sep 2, 2019

@weissi @artemredkin Thank you for your feedback, I'm going to fix this.

@PopFlamingo
Copy link
Contributor Author

Issues should now be fixed, just waiting to know what you think of the latest changes :). Formatting issues are also probably fixed now.

Copy link
Contributor

@weissi weissi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! @adtrevor would you mind creating one new unit test that deliberately returns futures from the wrong eventloop just to check everything still works?

@weissi
Copy link
Contributor

weissi commented Sep 2, 2019

@swift-server-bot add to whitelist

@weissi
Copy link
Contributor

weissi commented Sep 2, 2019

@swift-server-bot test this please

@PopFlamingo
Copy link
Contributor Author

PopFlamingo commented Sep 2, 2019

@weissi

would you mind creating one new unit test that deliberately returns futures from the wrong eventloop just to check everything still works?

The testGetWithDifferentEventLoopBackpressure already tests this using TestHTTPDelegate which I modified to allow initialising it using TestHTTPDelegate(backpressureEventLoop: external.next()) where external is a completely different event loop group! :)

@weissi
Copy link
Contributor

weissi commented Sep 2, 2019

@artemredkin how does this look to you?

@tanner0101 / @ianpartridge / @ldewailly / @tomerd any input on the API change?

This commit fixes #95 by always hopping event loop futures received from
the delegate to the right event loop. This could be a source of bugs if
the library users forgot to hop(to:) futures from their delegates
implementations.
@PopFlamingo
Copy link
Contributor Author

All issues should now be fixed and if no one has additional comments maybe this can now be merged? cc @weissi @artemredkin

Copy link
Contributor

@weissi weissi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, lgtm!

@weissi
Copy link
Contributor

weissi commented Sep 5, 2019

@swift-server-bot add to whitelist

@weissi
Copy link
Contributor

weissi commented Sep 5, 2019

@swift-server-bot test this please

@weissi weissi merged commit 244aea6 into swift-server:master Sep 6, 2019
@PopFlamingo PopFlamingo deleted the fix95 branch September 6, 2019 22:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⚠️ semver/major Breaks existing public API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

client needs to tolerate futures from arbitrary EventLoops
5 participants