-
Notifications
You must be signed in to change notification settings - Fork 125
add NIO event loop as an argument for execute #79
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good but needs a test
@weissi what do you think we need to test? that we use event loop we pass in? |
Two things:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@artemredkin, could we do the same for execute(request: Request, deadline: NIODeadline?)
? In the case of file upload we wouldn't normally use a HTTPClientResponseDelegate
@ldewailly done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Thanks @artemredkin
I think in its current state, in case of redirect the provided In general, is this API really a good idea? I'm thinking about the future connection pooling. What happens if the pooled connection lives on a different event loop? Should the client then not use this connection and create a new one? Or hop to the event loop of the connection and hop back only in the end? What should happen during the delegate callbacks? On which loop will those be executed? My understanding was: If you want to tightly control on which event loop the client executes, then initialize it witch a single event loop instead of a event loop group. WDYT? |
The pool could be keyed on the event loop too but that would as you point out mean that we possibly create more connections than necessary to avoid hopping.
Good point. That is achievable today through I think I'm with @t089 and am unsure if we really need this API or if we should just use a new |
I'm a bit inclined to want to say that the Client should hide this from users. Creating new clients per event loop seems like an excessive construction. Why not use the event loop as part of the connection key? Users that don't pass an event loop to This is strictly no less efficient than creating new clients for every loop. |
This sounds doable, although I wonder: if we manufacture a new connection for the explicitly requested event loop, should this connection then also become part of the connection pool? Because in that case, the pool would possibly contain connections that live on event loops that are completely out of the control of the Client. Not sure if this would cause a problem?! It's a bit unfortunate to discuss the impact of this patch on a feature that does not even exist yet. FWIW, in the current state I would say the |
Yeah, the connection should be part of the pool. Not sure what you mean by an event loop "out of control of the client" though: can you clarify? |
Yeah, maybe that is also a non-issue. But I was thinking of this scenario:
|
Yeah, good call, I think the client should confirm that the event loop for the connection is within its event loop group. |
So, should connections on "external" event loops become part of the pool or not? |
The client should refuse to make them, to avoid the question being relevant. 😁 |
Ahhhh ok, I totally missed that use case: You created the client with an ELG and you want to make sure that a subsequent request is executed on a specific EL of this ELG. Yeah, that's a very good use case. 👍 |
is there a way to test if EL is part of our ELG? |
Yes, ELGs expose a property that shows you the loops in them. |
For the case of a connection pool, I wonder what's the cost of hopping to a different event loop (even repeatedly) versus generating a completely new connection to match the event loop requirement, isn't the former typically much less expensive than the latter since memory is orders of magnitude faster than network IO? In this case, wouldn't it have the risk of causing worse performance when the user actually thinks they are doing an optimisation? Maybe we could do the following with the
What do you think? |
In general, yes, for a simple request you probably gain nothing by establishing a new TCP connection on your loop instead of reusing one on a different loop. However, if you are streaming a very large request or response body, you will need to incur way more coordination overhead, and in those cases it is often worth trying to line up the loops. I think your idea is good, but we should consider extending the API to allow users who know they want it to demand a connection on a specific loop. |
@Lukasa I see, so a finer grained preference? Why not something such as: enum EventLoopPreference {
case indifferent
case prefers(EventLoop)
case requires(EventLoop)
}
The current implementation would likely treat |
@adtrevor This might be the right idea. I'm just a little worried that right now we're probably not able to express all the things we want to express in the future and the public struct EventLoopPreferrence {
private enum Preferrence {
case .indifferent
case .prefers(EventLoop)
/* this is private, we can extend in the future */
}
private var preferrence: Preferrence
public static let indifferent = EventLoopPreferrence(preferrence: .indifferent)
public static func prefers(_ eventLoop: EventLoop) = EventLoopPreferrence(preferrence: eventLoop)
}
extension EventLoopPreferrence: NilLiteralConvertible {
/* make `nil` equal to `.indifferent` */
} if we do this we support the following on day 1: Obviously if we think Needless to say this is irrelevant if we don't think we don't need this kind of feature. |
Yeah, I think a finer-grained preference control is good. I like that idea, and think if we go with it we should adopt @weissi's suggestion. I also agree with @artemredkin's reminder that we should only allow users to ask for an event loop from the group the client is using. |
@weissi Thank you, I already saw this pattern in NIO and I like it. |
public static let indifferent = EventLoopPreferrence(preferrence: .indifferent) | ||
/// Library will try to use provided event loop if possible. | ||
public static func prefers(_ eventLoop: EventLoop) -> EventLoopPreferrence { EventLoopPreferrence(preferrence: .prefers(eventLoop)) } | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Preference only has one 'r'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops, fixed, thanks!
This part is still missing, isn't it? Should we add a test for it? |
public static let indifferent = EventLoopPreference(preference: .indifferent) | ||
/// Library will try to use provided event loop if possible. | ||
public static func prefers(_ eventLoop: EventLoop) -> EventLoopPreference { | ||
return EventLoopPreference(preference: .prefers(eventLoop)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the parameter shouldn't have a name here, "preference" is duplicated. Should be EventLoopPreference(.prefers(eventLoop))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea, fixed!
@artemredkin Thanks, that's great! |
…ion that EL must be part of ELG
@t089 good catch, thank you! updated the PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
Note, that redirects will ignore the preference parameter, won't they?
|
Also in the current implementation |
@t089 The issue if we use |
Ah got it, thanks! |
Indeed looks like this part is missing? |
Sorry, I merged because I didn't see this: Created issue #88 |
Addresses #78