Skip to content

Conversation

@WyriHaximus
Copy link
Member

@WyriHaximusWyriHaximus commented Feb 27, 2019

By using the happy eye balls algorythm as descripted in RFC6555 and
RFC8305 it will connect to the quickest responding server with a
preference for IPv6.

@WyriHaximusWyriHaximus added this to the v1.3.0 milestone Feb 27, 2019
@WyriHaximusWyriHaximus requested review from clue and jsorFebruary 27, 2019 21:32
@WyriHaximusWyriHaximusforce-pushed the happy-eye-balls branch 6 times, most recently from 4662be9 to ac92884CompareMarch 5, 2019 21:46
@WyriHaximusWyriHaximus marked this pull request as ready for review March 5, 2019 21:46
@WyriHaximus
Copy link
MemberAuthor

This PR is now ready for review. A follow up will be filed to replace the DnsConnector with the HappyEyeBallsConnector in the Connector an upcoming PR.

@WyriHaximusWyriHaximusforce-pushed the happy-eye-balls branch 2 times, most recently from 89c9769 to e4676eaCompareMarch 6, 2019 16:49
@WyriHaximusWyriHaximusforce-pushed the happy-eye-balls branch 2 times, most recently from 46a9866 to 25c1ecdCompareMay 2, 2019 06:25
@WyriHaximus
Copy link
MemberAuthor

Ping @clue && @jsor did some major refactoring on this PR and it is now ready few review

Copy link
Member

@clueclue left a 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)

@WyriHaximusWyriHaximusforce-pushed the happy-eye-balls branch 2 times, most recently from 3117a07 to 8fa1d3eCompareMay 18, 2019 22:43
@WyriHaximus
Copy link
MemberAuthor

@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?

Thanks for the review, I've addressed those points.

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)

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 Connector class 😄 .

Copy link
Member

@clueclue left a 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.

@WyriHaximus
Copy link
MemberAuthor

@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.

@WyriHaximusWyriHaximusforce-pushed the happy-eye-balls branch 2 times, most recently from 1326b88 to 335cdcbCompareJune 27, 2019 15:36
@WyriHaximus
Copy link
MemberAuthor

@clue oki updated to after your comments

Copy link
Member

@clueclue left a 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! :shipit: 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 👍

@WyriHaximus
Copy link
MemberAuthor

@clue working on the tests now, noticed the same thing this morning. 15% coverage to go 🎉

@WyriHaximusWyriHaximusforce-pushed the happy-eye-balls branch 4 times, most recently from c886e32 to d227b9cCompareAugust 25, 2019 19:43
@WyriHaximus
Copy link
MemberAuthor

We should assert that a second connection will not be attempted while the first one is pending for less than 0.1 seconds.

We should assert that this "next connection" timer is started.

We should assert that a second connection attempt is started when the first attempt is still pending, but the timer fired.

Likewise, add similar tests to check variations of IPv4/IPv6 attempts depending on DNS resolution etc.

❌ (working on it)

@WyriHaximusWyriHaximusforce-pushed the happy-eye-balls branch 4 times, most recently from dcc19c6 to 22d2f6bCompareAugust 29, 2019 19:37
@WyriHaximus
Copy link
MemberAuthor

Likewise, add similar tests to check variations of IPv4/IPv6 attempts depending on DNS resolution etc.

Copy link
Member

@clueclue left a 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;
}
Copy link
Member

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 = newPromise\Deferred();
$deferred = newPromise\Deferred();

$timer = $that->loop->addTimer($that::RESOLVE_WAIT, function () use ($deferred, $ips){
Copy link
Member

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?

Copy link
MemberAuthor

@WyriHaximusWyriHaximusSep 20, 2019

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()));
}
}
Copy link
Member

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.

Copy link
MemberAuthor

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.

@WyriHaximusWyriHaximusforce-pushed the happy-eye-balls branch 3 times, most recently from e73fa33 to 888941fCompareSeptember 20, 2019 15:46
@WyriHaximus
Copy link
MemberAuthor

@clue decreased tests time, they're still slower then before but that's due to the timings involved.

@clue
Copy link
Member

clue commented Sep 21, 2019

@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; returntrue})); // continue with test$this->assertNotNull($timer); $timer();

@WyriHaximus
Copy link
MemberAuthor

@clue yeah this is going to be fun 🤐

@WyriHaximus
Copy link
MemberAuthor

@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.

Copy link
Member

@clueclue left a 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! :shipit:

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
Copy link
MemberAuthor

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
Copy link
MemberAuthor

Choose a reason for hiding this comment

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

algorithm

@WyriHaximus
Copy link
MemberAuthor

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.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@WyriHaximus@clue@jsor