0.0.6 • Published 2 years ago

@balena/happy-eyeballs v0.0.6

Weekly downloads
-
License
ISC
Repository
github
Last release
2 years ago

@balena-io/happy-eyeballs

This package patches NodeJS's http(s).Agent to implement the IETF standard, "Happy Eyeballs 2" (rfc8305).

It improves client performance and reliability by trying concurrently trying multiple ip addresses for a given host name. See Explanation for more detail.

Installation

npm i --save-dev @balena/happy-eyeballs
yarn add --dev @balena/happy-eyeballs

Quick Usage

To use this library, simply import

import '@balena/happy-eyeballs/eye-patch';

or

require('@balena/happy-eyeballs/eye-patch')

to the top of your .js/.ts entry file.

Note: this will replace http.Agent.prototype.createConnection and https.Agent.prototype.createConnection, but it tries to preserve existing functionality as much as possible.

Explicit Usage

If you want to be more explicit, you can explicitly patch the http(s).Agent:

import { patch } from '@balena/eye-patch';
import { Agent as HttpAgent } from 'http';
import { Agent as HttpsAgent } from 'https';

patch(HttpAgent, {delay: 300});
patch(HttpsAgent, {delay: 300});

Although, this is exactly what the import '@balena/happy-eyeballs/eye-patch'; does anyway.

Note that delay refers to the delay before attempting the next addresses. This is the delay browsers use.

Later you can unpatch, which will undo the last patch:

unpatch([HttpsAgent, HttpAgent])

or reset to the original values of an agent:

reset([HttpsAgent, HttpAgent])

Also, note that the default is HttpAgent and HttpsAgent, so this has the same effect as

reset()

And that goes for patch and unpatch too.

You could also implement your own agent and replace the createConnection method:

import { createConnection } from '@balena/happy-eyeballs';
import { Agent as HttpAgent } from 'http';
import { Agent as HttpsAgent } from 'https';

export class MyHttpAgent extends HttpAgent {
  createConnection = createConnection;
  delay = 250;
}

export class MyHttpsAgent extends HttpsAgent {
  createConnection = createConnection;
  delay = 250;
}

This does basically the same thing as the previous examples though.

Explanation

Essentially, the algorithm amounts to this:

  1. Receive a hostname
  2. Have we connected to this host before?
  • If yes:
    • Try the family (Ipv4 or IPv6) of last successful connection if we have connected to this host before
    • If connection is not successful within 300ms, proceed to next step
  • If no: proceed to next step.
  1. Did the DNS lookup return both IPv4 and IPv6 addresses?
  • If yes: try, both addresses concurrently until all have been tried
  • If no: just try the address of the existent family
  1. Proceed with each address in chain, trying both families concurrently until either: . A connection is made . All connection attempts time out *. All connection attempt fail
  2. If no connection was successful, return error of the first connection attempt or a "time out" error if all connections timed out