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

comrade

v0.0.3

Published

Find and control servers in a cluster via a common datastore

Downloads

4

Readme

Comrade

This isn't done yet. The API will change in ways that will break stuff. If you use this, make sure you check the version before deploying to production.

What is Comrade?

Comrade has the following features:

  • Enable Node.js services in a cluster to find each other by saving their configurations to a common database (currently Google Cloud Datastore. More to come soon).
  • Enable Node.js servers to know when they should die and exit gracefully on their own.
  • Allow administrators to deploy/kill/restart Node.js services without having to access the machine in which it is running.

Why?

See the Motivation page in the wiki

API

This package contains two classes. Member and Client. Member reports one node's status to the rest of the cluster, and Client is used to get information about nodes in the cluster.

comrade.Member

new Member(options)

  • options a set of configurable options to set on the Member
    • role (required) the role of this node (e.g. appserver, loadbalancer, etc.)
    • options.googleDataset (required) a gcloud Dataset instance. See gcloud-node
    • options.id (optional) the unique ID of the member. If not set, a UUID is created.
    • options.googleDatasetNamespace (optional) the GCD namespace. If not set, the default for the given dataset is used.
    • options.googleDatasetKind (optional) the GCD kind to use. Defaults to ComradeServer
    • options.metadata (optional) an object containing information about the server (IP, port, etc.)

By using different namespaces or kinds, you can separate nodes into different environments.

    var http = require('http')
    var Member = require('comrade').Member
    var member = new Member({
      googleDataset: require('./my-google-dataset'),
      role: process.env.SERVER_ROLE,
      metadata: {
        ip: process.env.PUBLIC_IPV4,
        port: process.env.LISTEN_PORT
      }
    })
    var server = http.createServer(function(){/*do something*/})
    server.listen(process.env.LISTEN_PORT)
    member.start()

member.start()

Every 10 seconds, updates the database to tell other comrades the server is running, and checks if it needs to exit.

Event: 'shutdown'

Emitted when the member has been told to shutdown.

    var http = require('http')
    var Member = require('comrade').Member
    var member = new Member({
      googleDataset: require('./my-google-dataset'),
      role: process.env.SERVER_ROLE,
      metadata: {
        ip: process.env.PUBLIC_IPV4,
        port: process.env.LISTEN_PORT
      }
    })
    var server = http.createServer(function(){/*do something*/})
    server.listen(process.env.LISTEN_PORT)
    member.once('shutdown',function(){
      console.log('Closing server in 30 seconds...')
      setTimeout(function(){
        var interval = setInterval(function(){
          server.getConnections(function(err,connections){
            console.log('Open connections: '+connections)
          })
        },1000)
        server.close(function(){
          clearInterval(interval)
          console.log('Server closed')
          cache.clear()
        })
      },30000)
    })

comrade.Client

new Client(options)

  • options a set of configurable options to set on the Client
    • options.googleDataset (required) a gcloud Dataset instance. See gcloud-node.

    • options.googleDatasetNamespace (optional) the GCD namespace. If not set, the default for the given dataset is used.

    • options.googleDatasetKind (optional) the GCD kind to use. Defaults to ComradeServer

    • options.healthCheck (optional) custom health check function to see if each server is healthy. If not set, checks if member.updated is less than 60 seconds in the past.

        /*
          This example uses the default GCD namespace and kind options, with a
          custom health check that polls an endpoint on each member. If the 
          member responds with the correct ID it is healthy.
        */
        var comrade = require('comrade')
        var request = require('request')
        var client = new comrade.Client({
          googleDataset: require('./google-dataset'),
          healthCheck: function(memberData,callback){
            if(memberData.role == 'loadbalancer'){
              var timediff = Date.now() - memberData.updated
              callback(timediff < 60000)
            }
            else{
              var url = ['http://',memberData.metadata.ip,':',
                memberData.metadata.port,'/comrade_health_check'].join('')
              request.get({
                url: url
              },function(e,r,b){
                try{
                  var data = JSON.parse(b)
                  callback(!e && data.id == memberData.id)
                }
                catch(e){
                  callback(false)
                }
              })
            }
          }
        })
    • options.roles (optional) specify how members with certain roles should be treated. For example, set the minimum required number of servers to keep alive.

      new comrade.Client({
        ...
        roles: {
          app: {
            minMembers: 3 
            /* when using killOldestMember, don't kill a server with role
             "app" if there are not more than 3 servers. Default is 1. */
          },
          crawler: {
            minMembers: 0
            /* sometimes it's ok to have 0 healthy instances of a certain
            role. For example if you have a server that scrapes a third party
            website periodically, you don't need more than one machine doing
            that, and it's ok if the single machine shuts down for a minute or
            two. */
          }
        }
      })

client.getMembers(options,callback)

  • options a set of configurable options

    • options.role limit the results to contain only members with this a certain role.
    • options.alive if true, returns servers that have not started shutting down yet. If false, returns servers that have received the signal to shutdown.
    • options.healthy if true, returns servers that have passed the health check. If false, returns servers that have failed the health check.
    • options.stale if true, return servers that have been dead or unhealthy for more than an hour. If false, returns servers that have not been dead or unhealthy for more than an hour.
  • callback Function

      client.getMembers({
        role: 'app',
        alive: true
      },function(err,servers){
        /*
          err: gcloud error or null if successful
          servers: array of server data
        */
        servers.forEach(function(server){
          console.log(server.metadata.ip+':'+server.metadata.port)
        })
      })
      

###client.killMember(id,callback)

  • id the ID of the server to shut down.
  • callback Function

Tells the specified server to start shutting down.

###client.killOldestMember(options,callback)

  • options configurable set of options (same as client.getServer)
  • callback Function

Kills the server with the earliest creation date.

###client.clearStaleMembers(callback)

  • callback Function

Deletes entities for servers which have been dead or unhealthy from GCD. Run this periodically to lower the number of read operations when using the client.

##Examples

@TODO

##@TODO

  • Finish documentation
  • CLI
  • Other datastores