-
-
Notifications
You must be signed in to change notification settings - Fork 156
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
Implement the Happy Eye Balls RFC's #196
Conversation
4662be9
to
ac92884
Compare
This PR is now ready for review. A follow up will be filed to replace the |
89c9769
to
e4676ea
Compare
46a9866
to
25c1ecd
Compare
25c1ecd
to
6d7fc27
Compare
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.
@WyriHaximus Thank you very much for working on this, this is one of the features that is very high on my personal wishlist! ❤️
However, I realize that the implementation is anything but trivial. I've added some remarks to some places that look odd to me, perhaps you can take a look?
That being said, once all implementation issues are resolved, I wonder what's the best path forward to ensure a safe rollout of this feature in the future? Perhaps it makes sense to first enable this without IPv6 support to see the initial implementation does not break any existing implementations? I can see some (legacy) use cases where it may be desirable to explicitly disable IPv6 because the downstream application might not be IPv6-ready? (think database fields storing an address in a fixed length field)
3117a07
to
8fa1d3e
Compare
🎉 !!!
Thanks for the review, I've addressed those points.
Not entirely sure yet how to do that. What I want to do is write a follow up PR that initially will go full in on happy-eyeballs. And then we'll comes up during the discussion on that PR how we're shaping that. Because I'm pretty sure we can solve this with a flag on the |
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.
@WyriHaximus Thanks for the update! This PR/implementation is not exactly trivial, so I've added some remarks to see if we can avoid some of its complexity. Let me know what you think about it.
It isn't trivial at all. I'll be adding links to certain implementation details linking to the RFC('s) where applicable to understand the why for those things. |
1326b88
to
335cdcb
Compare
@clue oki updated to after your comments |
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.
@WyriHaximus Thank you very much, the additional comments really help, I think we're slowly getting there! I've noticed this code currently has ~85% coverage and I've added some remarks to perhaps improve this.
Consider my structural concerns resolved, I'd love to get this in once we've added some additional tests, given the inherent complexity of this algorithm 👍
@clue working on the tests now, noticed the same thing this morning. 15% coverage to go 🎉 |
335cdcb
to
82ce847
Compare
c886e32
to
d227b9c
Compare
✅
✅
✅
❌ (working on it) |
dcc19c6
to
22d2f6b
Compare
✅ |
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.
@WyriHaximus Thanks for the update! All my local tests have succeeded with the updated version 👍
Unfortunately, the test suite now takes ~1.8 minutes(!) to run, whereas the old version took ~8 seconds. Perhaps rebase on #207 which should further improve this and then take a look at why the tests are so slow?
The test suite should probably use a mocked look (unless it's an integration test) and use $promise->then($this->expectCallableOneWith($expectedValue))
instead of running and awaiting the loop. In particular, all timers should be avoided unless absolutely required.
|
||
if ($that->timer instanceof TimerInterface) { | ||
return; | ||
} |
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.
Can you take a look at this again? I can't reproduce this locally anymore, but I don't see any change here?
$ipv4Deferred = new Promise\Deferred(); | ||
$deferred = new Promise\Deferred(); | ||
|
||
$timer = $that->loop->addTimer($that::RESOLVE_WAIT, function () use ($deferred, $ips) { |
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.
Promise cancellation doesn't seem to cancel this timer?
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.
Addressed that
if (count($ipv4) > 0) { | ||
$this->tcp->expects($this->at($i++))->method('connect')->with($this->equalTo('scheme://' . array_shift($ipv4) . ':80/?hostname=google.com'))->will($this->returnValue(Promise\resolve())); | ||
} | ||
} |
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.
Not a big fan of having this logic in the test suite. It's my understanding this should be rather static and/or multiple independent tests. After all, where are the tests for this test suite? 👀 I'm okay with this for now.
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.
Not a big fan of it either. But this lets us test different lenghth IPvX responses against several tests. This uncovered certain edge cases in the past and help me first the issue you commented about on line 60.
e73fa33
to
888941f
Compare
@clue decreased tests time, they're still slower then before but that's due to the timings involved. |
@WyriHaximus Can confirm the test time is now down to ~50s on my machine. There still seem to be plenty of timers, so I would still suggest mocking the loop and explicitly invoking the timer callback like this: $loop = $this->createMock(LoopInterface::class);
$timer = null;
$loop->expects($this->once())->method('addTimer')->with(2.0, $this->callback(function ($cb) use (&$timer) {
$timer = $cb;
return true;
}));
// continue with test
$this->assertNotNull($timer);
$timer(); |
@clue yeah this is going to be |
888941f
to
29695e1
Compare
@clue went for a slightly different approach that still does a full run with an actual event loop and timers, but I've speed it up instead by a factor of 10. |
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.
@WyriHaximus Thanks for keeping up with this, I can confirm that test time changed to ~13s (~8s prior to this patch) 👍 Now let's get this feature shipped!
README.md
Outdated
It will then replace the hostname in the destination URI with this IP's and | ||
append a `hostname` query parameter and pass this updated URI to the underlying | ||
connector. | ||
The Happy Eye Balls algorythm describes looking the IPv6 and IPv4 address for |
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.
algorithm
README.md
Outdated
The `HappyEyeBallsConnector` class implements the | ||
[`ConnectorInterface`](#connectorinterface) and allows you to create plaintext | ||
TCP/IP connections to any hostname-port-combination. Internally it implements the | ||
happy eyeballs algorythm from [`RFC6555`](https://tools.ietf.org/html/rfc6555) and |
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.
algorithm
So @jsor spotted two typo's after approving, will fix those before merging 👍 |
By using the happy eye balls algorithm as described in RFC6555 and RFC8305 it will connect to the quickest responding server with a preference for IPv6.
29695e1
to
f2b5fc4
Compare
By using the happy eye balls algorythm as descripted in
RFC6555
andRFC8305
it will connect to the quickest responding server with apreference for IPv6.