-
Notifications
You must be signed in to change notification settings - Fork 117
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
[HTTP2] Create new connections during migration if needed #459
[HTTP2] Create new connections during migration if needed #459
Conversation
Sources/AsyncHTTPClient/ConnectionPool/State Machine/HTTPConnectionPool+HTTP1Connections.swift
Outdated
Show resolved
Hide resolved
createConnections.append( | ||
contentsOf: preferredEventLoopsOfPendingGeneralPurposeRequests.lazy | ||
/// we do not want to start additional connection for requests for which we already have starting or backing off connections | ||
.dropFirst(self.startingGeneralPurposeConnections) |
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.
Why are we using dropFirst
? Is the order of objects in this collection semantic? We don’t use it anywhere else in this function so why are we throwing those away?
self.connections.append(newConnection) | ||
self.connections.insert(newConnection, at: self.overflowIndex) | ||
self.overflowIndex = self.connections.index(after: self.overflowIndex) |
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.
I think we need more logic here! If we have 64 EventLoops and 64 requests that all require a different EL, we will blow through the default self.maximumAdditionalGeneralPurposeConnections
without checking.
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.
This is correct, however we can't close starting connections because ClientBoostrap
doesn't support it. What logic would you add instead?
self.connections.append(backingOffConnection) | ||
self.connections.insert(backingOffConnection, at: self.overflowIndex) | ||
self.overflowIndex = self.connections.index(after: self.overflowIndex) |
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.
Same as above.
// create new connections for requests with a required event loop | ||
let eventLoopsWithConnectionThatCanOrWillBeAbleToExecuteRequests = Set( | ||
self.connections.lazy | ||
.filter { | ||
$0.canOrWillBeAbleToExecuteRequests | ||
}.map { | ||
$0.eventLoop.id | ||
} | ||
) | ||
var createConnections = requiredEventLoopsOfPendingRequests.compactMap { eventLoop -> (Connection.ID, EventLoop)? in | ||
guard !eventLoopsWithConnectionThatCanOrWillBeAbleToExecuteRequests.contains(eventLoop.id) | ||
else { return nil } | ||
let connectionID = self.createNewOverflowConnection(on: eventLoop) | ||
return (connectionID, 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.
This is not in line, with how we currently process requests in http/1.1. For required eventLoops, we try to keep the number of starting
(in this case meaning connecting
and backingOff
) connections the same as the number of queued requests.
Sources/AsyncHTTPClient/ConnectionPool/State Machine/HTTPConnectionPool+HTTP1Connections.swift
Outdated
Show resolved
Hide resolved
Sources/AsyncHTTPClient/ConnectionPool/State Machine/HTTPConnectionPool+HTTP1Connections.swift
Show resolved
Hide resolved
Sources/AsyncHTTPClient/ConnectionPool/State Machine/HTTPConnectionPool+HTTP1StateMachine.swift
Outdated
Show resolved
Hide resolved
Sources/AsyncHTTPClient/ConnectionPool/State Machine/HTTPConnectionPool+HTTP1Connections.swift
Show resolved
Hide resolved
Sources/AsyncHTTPClient/ConnectionPool/State Machine/HTTPConnectionPool+RequestQueue.swift
Outdated
Show resolved
Hide resolved
Sources/AsyncHTTPClient/ConnectionPool/State Machine/HTTPConnectionPool+RequestQueue.swift
Outdated
Show resolved
Hide resolved
e7d43f3
to
b39c948
Compare
- new connections that are created after the http2 -> http1 migration should now more closely mimic the behaviour of the http1 state machine - API bounderies are now clearer
b39c948
to
2eb2afc
Compare
Sources/AsyncHTTPClient/ConnectionPool/State Machine/HTTPConnectionPool+HTTP1Connections.swift
Outdated
Show resolved
Hide resolved
Sources/AsyncHTTPClient/ConnectionPool/State Machine/HTTPConnectionPool+HTTP1Connections.swift
Outdated
Show resolved
Hide resolved
Sources/AsyncHTTPClient/ConnectionPool/State Machine/HTTPConnectionPool+HTTP1Connections.swift
Outdated
Show resolved
Hide resolved
1585eac
to
6b9d55b
Compare
Sources/AsyncHTTPClient/ConnectionPool/State Machine/HTTPConnectionPool+HTTP1Connections.swift
Outdated
Show resolved
Hide resolved
|
||
outerLoop: for (eventLoop, requestCount) in generalPurposeRequestCountGroupedByPreferredEventLoop { | ||
let connectionsToStart = max(requestCount - unusedGeneralPurposeConnections, 0) | ||
unusedGeneralPurposeConnections -= min(requestCount, unusedGeneralPurposeConnections) | ||
for _ in 0..<connectionsToStart { | ||
guard self.canGrow else { | ||
break outerLoop | ||
} | ||
connectionToCreate.append((self.createNewConnection(on: eventLoop), 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.
I think this is correct. However I think, we could make this code a little easier to read. Wdyt about creating a variable:
var neededGeneralPurposeConnections = max(requestCount - unusedGeneralPurposeConnections, 0)
and then decreasing the variable for each created connection? Break the loop as soon as the variable has reached 0
.
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.
I'm not sure if I fully understand what you mean. It seams you want to replace the for loop in line 620 with a while loop and exit it if we hit zero, which is exactly the same behaviour as the for loop. I would argue that the intent of the for loop is clearer (and safer) compared to a while true loop with a break on zero.
Or do you first want to sum up the actually number of neededGeneralPurposeConnections
regardless of event loop. Then we could replace the two for loops with only one while/for loop.
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 later. :)
Sources/AsyncHTTPClient/ConnectionPool/State Machine/HTTPConnectionPool+HTTP1StateMachine.swift
Outdated
Show resolved
Hide resolved
Sources/AsyncHTTPClient/ConnectionPool/State Machine/HTTPConnectionPool+HTTP1StateMachine.swift
Show resolved
Hide resolved
/// We need a connection for each queued request with a required event loop. | ||
/// Therefore, we look how many request we have queued for a given `eventLoop` and | ||
/// how many connections we are already starting on the given `eventLoop`. | ||
/// If we have not enough, we will create additional connections to have at least on connection per request. |
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.
Is the ///
intended?
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.
I have added three slashes in a couple of places. Do we have any style guide when to use three and when to use two? I slightly tend to like three slashes more because the non-monospaced font is a bit easier to read for me but I do not have a strong opinion on that topic.
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.
I think we use three in documentation comments (like above a method) and two inline. At least that's what I've seen (and done) so far.
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.
Number of small nits. But this a great patch.
Motivation
We potential need to create new connections during migration:
HTTP1 -> HTTP2:
HTTP2 -> HTTP1
Changes