All files / copacetic/lib/cluster attach.js

96.96% Statements 32/33
93.33% Branches 14/15
100% Functions 12/12
96.87% Lines 31/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 811x     10x 10x           1x               14x 14x                       14x 11x 11x   11x 1x     10x 7x 7x     7x 7x 1x     7x 1x   1x         3x 1x 1x 1x         3x 2x 1x     1x   1x       10x     1x  
const constants = require('./constants.js')
 
function addWorker (copacetic, worker, attachOptions) {
  try {
    copacetic.registerDependency({
      name: worker.id.toString(),
      level: attachOptions.dependency.level,
      strategy: { type: 'copacetic', opts: { timeout: 5000, nodeContext: worker } }
    })
  } catch (e) {
    Iif (!e.message || e.message.indexOf('already registered') === -1) {
      throw e
    }
    // was already registered, ignore safely
  }
}
 
function attachToClusterFactory (injector) {
  const clusterMessages = new (injector.provideOne('cluster-messages', false, true))({ metaKey: 'copacetic' })
  const cluster = injector.provideOne('cluster', false, true)
 
  /**
   * Register the cluster processes with copacetic.
   * If `cluster.isMaster` it will add all `workers` as dependencies and will be able to report their health.
   * Otherwise setup listeners so the worker know to reply to teh master process. You can get the full health of the cluster from the worker process by calling `Copacetic.checkCLuster()`.
   * @param {Copacetic} the instance of Copacetic the cluster should attach to.
   * @param {[Object]} Options for attaching. Only supports dependency.level.
   * @example
   * const healthChecker = new Copacetic()
   * Copacetic.cluster.attach(healthChecker, { dependency: { level: 'HARD' } })
   */
  return function attachToCluster (copacetic, attachOpts = {}) {
    attachOpts.dependency = attachOpts.dependency || {}
    attachOpts.dependency.level = attachOpts.dependency.level || 'HARD'
 
    if (copacetic.eventEmitterMode) {
      throw new Error('Cluster feature not available in event emitter mode')
    }
 
    if (cluster.isMaster) {
      for (const id in cluster.workers) {
        addWorker(copacetic, cluster.workers[id], attachOpts)
      }
 
      cluster.on('online', worker => addWorker(copacetic, worker, attachOpts))
      cluster.on('disconnect', (worker) => {
        copacetic.deregisterDependency(worker.id)
      })
 
      clusterMessages.on(constants.EVENT_NAMES.ASK_MASTER_HEALTH, (data, callback) => {
        copacetic.checkAll()
          .then(() => {
            callback(copacetic.healthReport)
          })
          // Sadly no `.catch` as cluster-messages doesn't really offer error handling. Better to leave as UnhandledPromiseRejection rather than stick an arbitrary console.error that won't match the logger format of parent service
      })
    } else {
      copacetic.checkCluster = () => {
        return new Promise((resolve, reject) => {
          clusterMessages.send(constants.EVENT_NAMES.ASK_MASTER_HEALTH, {}, (result) => {
            resolve(result)
          }) // same comment as above about error handling
        })
      }
 
      clusterMessages.on(constants.EVENT_NAMES.MASTER_ASKING_HEALTH, (data, callback) => {
        if (data.recipient !== cluster.worker.id) {
          return
        }
 
        copacetic.checkAll()
          .then(() => {
            callback(copacetic.healthReport)
          }) // same comment as above about error handling
      })
    }
    return { clusterMessages }
  }
}
module.exports = attachToClusterFactory