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

multiagent

v2.1.0

Published

Simple HTTP client with failover functionality for node.js and browsers

Downloads

8

Readme

multiagent

Simple HTTP client with failover functionality for node.js and browsers

It supports simple fallback addresses as well as dynamic service discovery using Consul.

Multiagent uses superagent under the covers and exposes most of its API as well as an additional promise interface (if native promises are available).

All browsers with ECMAScript 5 support should work.

Installation

node.js, browserify, webpack:

npm install --save multiagent

as a global script in the browser:

<script src="node_modules/multiagent/lib/browser.min.js"></script>

from a CDN:

<script src="https://npmcdn.com/multiagent/lib/browser.min.js"></script>

In case you load multiagent with a script reference into the browser, it will create the global variable multiagent.

Examples

Simple HTTP requests

Multiagent can be used as a simple HTTP client, pretty much as a drop-in replacement of superagent:

const agent = require('multiagent');

// create a request:
const req = agent.request('GET', 'http://domain.com');

// or use a shorthand (there's also: 'head', 'post', 'put', 'delete'/'del')
const req = agent.get('http://domain.com');

// execute a request, providing a callback:
req.end((err, res) => console.log(err || res.body));

// or instead, use the promise interface:
const promise = req.promise();
promise.then(res => console.log(res.body), err => console.log(err));

// you can also simply just call 'then' (or 'catch') on the request:
req.then(res => console.log(res.body), err => console.log(err));

HTTP client with failover

If you have your service running on multiple endpoints, you can provide a list of hard-coded server URLs and take advantage of multiagent's failover mechanism:

const agent = require('multiagent');

// create a client:
const client = agent.client({
  servers: ['http://sub1.abc.com', 'http://sub2.abc.com', 'http://sub3.abc.com']
});

// then do stuff:
client
  .get('/endpoint') // use just the path without host!
  .timeout(500) // used per individual call!
  .end((err, res) => console.log(err || res.body));

HTTP client with discovery using Consul

Instead of hard-coding your server URLs you can use a Consul server or cluster to dynamically resolve the base URLs for your service calls:

const agent = require('multiagent');

// create a client:
const client = agent.client({
  discovery: 'consul', // only possible value at the moment, more could be added in the future
  discoveryServers: ['http://consul1.abc.com', 'http://consul2.abc.com', 'http://consul3.abc.com'],
  serviceName: 'my-service'
});

// then do stuff:
client
  .get('/endpoint') // use just the path without host!
  .timeout(500) // used per individual service call!
  .end((err, res) => console.log(err || res.body));

Getting the server URLs without calling an endpoint

If you're just interested in the service URLs e.g. from Consul without actually calling any service endpoint, you can use the resolveServers function provided by the client instance:

const agent = require('multiagent');

// create a client:
const client = agent.client({
  discovery: 'consul',
  discoveryServers: ['http://consul1.abc.com', 'http://consul2.abc.com', 'http://consul3.abc.com'],
  serviceName: 'my-service'
});

// get the list of servers providing a callback:
client.resolveServers((err, servers) => console.log(err || servers));

// or use the promise interface:
client.resolveServers().then(servers => console.log(servers));

Advanced client options

For the client using simple failover you can pass the following additional options:

  • strategy: string, (sequentially|randomly|simultaneously), default: 'sequentially'
  • shouldFailover: function, default: (err, res) => err || res.status >= 400

For the client using Consul you can pass the following additional options:

  • serviceProtocol: string, (http|https), default: 'http'
  • serviceStrategy: string, (sequentially|randomly|simultaneously), default: 'sequentially'
  • discoveryTimeout: number, in milliseconds, default: 2000
  • discoveryStrategy: string, (sequentially|randomly|simultaneously), default: 'simultaneously'
  • refreshAfter: number, in milliseconds, default: 60000
  • shouldFailover: function, default: (err, res) => err || res.status >= 400
  • createConsulRequestPath: function, default: serviceName => `/v1/health/service/${encodeURIComponent(serviceName)}?passing=true` ,
  • createServerListFromConsulResponse: function, default: (body, serviceProtocol) => body.map(x => `${serviceProtocol}://${x.Service.Address}:${x.Service.Port}`)

Finetuning failover options on a per request basis

When you create a client with failover using agent.client({ /* options */ }) you can override the failover strategy as well as the failover criteria on a per request basis. This is sometimes useful when e.g. in a RESTful environment a response with status code 404 (not found) is a perfectly valid result and should not lead to any failover:

// create a client with default options for all requests issued using this client instance:
const client = agent.client({
  servers: ['http://sub1.abc.com', 'http://sub2.abc.com', 'http://sub3.abc.com'],
  strategy: 'simultaneously',
  shouldFailover: (err, res) => err || res.status >= 400
});

// this will execute the requests sequentially and NOT failover on a 404 status response,
// thus overriding the options 'strategy' and 'shouldFailover' set as default on the client:
client
  .get('/endpoint')
  .failover({ strategy: 'sequentially' })
  .failover({ shouldFailover: (err, res) => err || (res.status >= 400 && res.status !== 404) }) 

Supported API

The following functions from superagent are supported:

On the client

  • head
  • get
  • post
  • put
  • delete
  • del

Additionally:

  • request
  • resolveServers

On the request

  • set
  • query
  • send
  • type
  • accept
  • timeout
  • auth
  • redirects
  • attach
  • field
  • withCredentials
  • abort
  • end

Additionally:

  • failover
  • promise
  • then
  • catch

License

MIT