npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

grpclb

v1.3.4

Published

grpc load balancer for Node.js

Downloads

17

Readme

grpclb

grpc load balancer integrated with etcd for Node.js

Install

npm i grpclb grpc

grpclb lists grpc as its peerDependency not dependency because here

Server side

import { register } from 'grpclb';

const revoke = await register({
  server, // your grpc server instance
  etcdKV: { key, value }, // leave you to decide how to serialize service name, host, port into KV
  ttl: 10, // default 10 in seconds
  etcdHosts: hosts, // etcd hosts, or you can set as env var ETCD_HOSTS
});

// then you can revoke
// by direct call the revoke handler
revoke();

// or by shutting down the grpc server
server.tryShutdown(() => {});

Client side

  • client-side load balancing with round-robin strategy

We can't register custom service resolver util the C library exposes the api.

So we can implement client-side load-balancing on the other way: javascript Proxy

import { createGrpcProxy } from 'grpclb';
import { loadSync } from '@grpc/proto-loader';
import { loadPackageDefinition } from 'grpc';

// load .proto file
const packageDefinition = loadSync(PROTO_PATH);
// initialize into javascript object
const pkgDef = loadPackageDefinition(packageDefinition);

const proxy = await createGrpcProxy({
  etcdHosts: hosts, // etcd hosts, or you can set as env var ETCD_HOSTS
  target: pkgDef.helloworld, // your gRPC object, MUST be the package definition object
  parseKV, // how to extract service name, host, port from etcd key and value
});

// Every time you access the service object, you get the new servant address.
const servant = proxy.Greeter;

// The service was already initialized and
// you can just call the service method to send request
servant.sayHello({ name }, (error, response) => {});

For static generated grpc javascript codes

The Proxy way is not convenient. So grpclb also provides another api to do the load balancing:

import { createClientPool } from 'grpclb';
import { GreeterClient } from 'helloworld/static_codegen/helloworld_grpc_pb';
import { HelloRequest } from 'helloworld/static_codegen/helloworld_pb';

const pool = await createClientPool({
  Client: GreeterClient, // your client service
  parseKV, // how to extract service name, host, port from etcd key and value
  etcdHosts: hosts, // etcd hosts, or you can set as env var ETCD_HOSTS
});

// Every time you access the service object, you get the new servant address.
const servant = pool.get();

// The service was already initialized and
// you can just call the service method to send request
servant.sayHello(new HelloRequest(), (error, response) => {});

Notes

grpc as peerDependency, not dependency

Image you have two copies of grpc, it would look like:

├── node_modules
│   ├── grpclb
│   │   └── node_modules
│   │       └── grpc
│   └── grpc
└── src
    └── static_codegen
        ├── helloworld_grpc_pb.js
        ├── helloworld_pb.d.ts
        └── helloworld_pb.js
  • require('grpc') in src directory, no matter dynamic generated gRPC javascript code or static generated, would resolve to node_modules/grpc
  • require('grpc') in grpclb package would resolve to node_modules/grpclb/node_modules/grpc

Then initialization would throw error TypeError: Channel's second argument must be a ChannelCredentials. See details for this issue

List grpc as peerDependency can avoid this situation.