Skip to content
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

EventLoop preference overhaul #102

Merged
merged 1 commit into from
Sep 21, 2019
Merged

EventLoop preference overhaul #102

merged 1 commit into from
Sep 21, 2019

Conversation

weissi
Copy link
Contributor

@weissi weissi commented Sep 11, 2019

Motivation:

With #96 we changed HTTPClient.Task's eventLoop property to be currentEventLoop because we anticipated that it might change because of the connection pool work that's ongoing.
That however made the programming model rather hard because the user didn't get any guarantee anymore on which EventLoop the delegate would run.
With this patch, we're bringing eventLoop back which is the EventLoop the delegate will run on. Note that it's not necessarily the EventLoop the Channel will run on. If the user requires those to be the same, the can request that with EventLoopPreference.delegateAndChannel(on: eventLoop) rather than .indifferent or .delegate(on: eventLoop)

Modification:

Let the user select between:

  • .indifferent: I don't care about the EventLoop
  • .delegate(on: eventLoop): I want the delegate to be called on eventLoop and I would prefer the Channel to be on eventLoop too but I'm happy if not
  • .delegateAndChannel(on: eventLoop): I want Channel and delegate to live on eventLoop

Result:

@weissi
Copy link
Contributor Author

weissi commented Sep 11, 2019

CC @adtrevor

@weissi weissi added the semver/major For PRs that when merged cause a bump of the major version, ie. x.0.0 -> (x+1).0.0 label Sep 11, 2019
@weissi weissi added this to the 1.0.0 milestone Sep 11, 2019
///
/// In most cases you should use `currentEventLoop` instead
private var _currentEventLoop: EventLoop
/// The `EventLoop` the delegate will be executed on.
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe there should also be a public accessible property to the channel's 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.

What would the use-case be?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Happy to add now or later if we feel there’s a compelling-enough reason

Copy link
Contributor

Choose a reason for hiding this comment

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

I was thinking about the backpressure futures of the delegate: performance wise, it's best to return one from the same event loop as the channel, which wouldn't be possible anymore if there is no access to the channel event loop.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm inclined to say that if that really matters much, the user should've chosen .delegateAndChannel(on: ...) and therefore the channel's EL == delegate's EL. @Lukasa what do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it’s reasonable to be able to ask for the delegate loop.

Copy link
Contributor

@PopFlamingo PopFlamingo Sep 19, 2019

Choose a reason for hiding this comment

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

@Lukasa The delegate EventLoop should already be accessible with the eventLoop property, but I was thinking about the channel's EventLoop.

To give a more concrete example of what worries me, if you look at what happens in the ResponseAccumulator, the newest changes are doing this:

public func didReceiveHead(task: HTTPClient.Task<Response>, _: HTTPResponseHead) -> EventLoopFuture<Void> {
    return task.eventLoop.makeSucceededFuture(())
}

If no event loop preference is set, task.eventLoop can be completely different from the channel event loop.

But this means that in this part:

self.delegate.didReceiveBodyPart(task: self.task, body)
                    .hop(to: context.eventLoop)

The cost of hopping will be quite big especially something that's going to be called so much often.

It's true that for some uses .delegateAndChannel(on: ...) would probably be the best options, but for the delegates like ResponseAccumulator this isn't needed and yet being unable to access the channel el would loose performance.

Copy link
Contributor

@PopFlamingo PopFlamingo Sep 19, 2019

Choose a reason for hiding this comment

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

On the other hand if letting public access to the channel event loop risks introducing too many errors on lib user side, maybe we could actually allow returning nil for the delegates that don't need backpressure? This would allow the client to choose the right event loop to get the best performance.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, I don't think it's worth exposing the channel event loop at this time. I understand the concern, and I think we can address it in the future, but for now I don't think I'd really bother. The performance concern is not really large enough (IMO) to justify it right now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@adtrevor if you really need that kind of performance, I'd say just use .delegateAndChannel(on: ...) and then the delegate and the Channel's EL are guaranteed to be the same. If we truly find that there are important use-cases to get the Channel's El we can, as Cory points out, add that at any point without breaking API.

@PopFlamingo PopFlamingo mentioned this pull request Sep 14, 2019
8 tasks
@weissi
Copy link
Contributor Author

weissi commented Sep 20, 2019

@artemredkin I fixed the merge conflicts now.

@artemredkin
Copy link
Collaborator

Do you want to merge of wait for @Lukasa's approval?

@weissi weissi merged commit 513be15 into swift-server:master Sep 21, 2019
@weissi weissi deleted the jw-new-el-pref branch September 21, 2019 19:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver/major For PRs that when merged cause a bump of the major version, ie. x.0.0 -> (x+1).0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

programming model questions
4 participants