Socket
Book a DemoInstallSign in
Socket

envoy-node-boilerplate

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

envoy-node-boilerplate

Source
npmnpm
Version
0.0.3
Version published
Weekly downloads
10
400%
Maintainers
1
Weekly downloads
 
Created
Source

Envoy Node Boilerplate

Travis Coverage Status npm version npm license

This is a boilerplate to help you adopt Envoy.

There are multiple ways to config Envoy, one of the convenience way to mange different egress traffic is route the traffic by hostname (using virtual hosts). By doing so, you can use one egress port for all your egress dependencies:

listener:
- address: tcp://127.0.0.1:12345
  filters:
    - name: http_connection_manager
      config:
        codec_type: auto
        use_remote_address: true
        stat_prefix: my-service.egress
        route_config:
          virtual_hosts:
          - name: foo_cluster
            domains:
            - foo.service:10080 # Do not miss the port number here
            routes:
            - prefix: /
              cluster: foo_cluster
          - name: bar_cluster
            domains:
            - bar.service:10081 # Do not miss the port number here
            routes:
            - prefix: /
              cluster: bar_cluster
        filters:
        - name: router
          config:
            dynamic_stats: true
        tracing:
          operation_name: egress
        access_log:
        - path: /tmp/envoy.my-service.egress.log
          filter:
            type: not_healthcheck

But it will bring you new problem, your code is becoming verbose:

  • routing traffic to 127.0.0.1:12345 where egress port is listening
  • setting host headers for each request
  • propagating the tracing information

And this library is going to help you deal with these things elegantly.

First, let's tell the library where the egress port is binding. A recommended way is to set the information on the ingress header by request_headers_to_add:

request_headers_to_add:
- key: x-tubi-envoy-egress-port
  value: "12345"
- key: x-tubi-envoy-egress-addr
  value: 127.0.0.1

You can also set this by the constructor parameters of EnvoyContext.

High level APIs

For HTTP, you can new the client like this:

const { EnvoyHttpClient, HttpRetryOn } = require("envoy-node-boilerplate");

async function awesomeAPI(req, res) {
  const client = new EnvoyHttpClient(req.headers);
  const url = `http://foo.service:10080/path/to/rpc`
  const request = {
    message: "ping",
  };
  const optionalParams = {
    // timeout 1 second
    timeout: 1000,
    // envoy will retry if server return HTTP 409 (for now)
    retryOn: [HttpRetryOn.RETRIABLE_4XX],
    // retry 3 times at most
    maxRetries: 3,
    // each retry will timeout in 300 ms
    perTryTimeout: 300,
  };
  const serializedJsonResponse = await client.post(url, request, optionalParams);
  res.send({ serializedJsonResponse });
  res.end();
}

For gRPC, you can new the client like this:

const grpc = require("grpc");
const { envoyProtoDecorator, GrpcRetryOn } = require("envoy-node-boilerplate");

const PROTO_PATH = __dirname + "/ping.proto";
const Ping = grpc.load(PROTO_PATH).test.Ping;

// the original client will be decorated as a new class
const PingClient = envoyProtoDecorator(Ping);

async function awesomeAPI(call, callback) {
  const client = new PingClient("bar.service:10081", call.metadata);
  const request = {
    message: "ping",
  };
  const optionalParams = {
    // timeout 1 second
    timeout: 1000,
    // envoy will retry if server return DEADLINE_EXCEEDED
    retryOn: [GrpcRetryOn.DEADLINE_EXCEEDED],
    // retry 3 times at most
    maxRetries: 3,
    // each retry will timeout in 300 ms
    perTryTimeout: 300,
  };
  const response = await client.pathToRpc(request, optionalParams);
  callback(undefined, { remoteResponse: response });
}

Low level APIs

If you want to have more control of your code, you can also use the low level APIs of this library:

const { envoyFetch, EnvoyContext, EnvoyHttpRequestParams, EnvoyGrpcRequestParams } = require("envoy-node-boilerplate");

// ...

const context = new EnvoyContext(
  headerOrMetadata,
  // specify port if we cannot indicate from
  // - `x-tubi-envoy-egress-port` header or
  // - environment variable ENVOY_DEFAULT_EGRESS_PORT
  envoyEgressPort,
  // specify address if we cannot indicate from
  // - `x-tubi-envoy-egress-addr` header or
  // - environment variable ENVOY_DEFAULT_EGRESS_ADDR
  envoyEgressAddr
);

// for HTTP
const params = new EnvoyHttpRequestParams(context, optionalParams);
envoyFetch(params, url, init /* init like original node-fetch */)
  .then(res => {
    console.log("envoy tells:", res.overloaded, res.upstreamServiceTime);
    return res.json(); // or res.text(), just use it as what node-fetch returned
  })
  .then(/* ... */)

// for gRPC
const client = new Ping((
  `${context.envoyEgressAddr}:${context, envoyEgressPort}`, // envoy egress port
  grpc.credentials.createInsecure()
);
const requestMetadata = params.assembleRequestMeta()
client.pathToRpc(
  request,
  requestMetadata,
  {
    host: "bar.service:10081"
  },
  (error, response) => {
    // ...
  })

Check out the detail document if needed.

License

MIT

Credits

FAQs

Package last updated on 22 Dec 2017

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts