es6/Services/Loop.js
import Promise from 'bluebird'
import Expressive from '../utils/Expressive'
import * as Time from '../utils/Time'
import Events from '../utils/Events'
/**
* a basic polling Loop which rejects actions until the previous action has completed
*
* @class Loop
*/
export default class Loop extends Expressive {
/**
* Bubbles async errors into the main process so we can kill this Wyst node if something is awry
*
* @method bubble
* @param {Error} err The error to throw
*/
static bubble (err) {
throw err
process.exit(1)
}
/**
* constructor
*
* @method constructor
*/
constructor (config = {}) {
super()
this.interval = config.interval || Time.seconds(1)
this._paused = true
return Promise.resolve(this)
}
/**
* starts Polling
*
* @method start
*/
start () {
this.togglePaused()
this.$ = setInterval( this.tick.bind(this), this.interval )
return this
}
/**
* stops Polling
*
* @method pause
*/
pause () {
this.togglePaused()
clearInterval(this.$)
return this
}
/**
* determines if we are paused or polling
*
* @method togglePaused
*/
togglePaused () {
this._paused = this._paused ? false : true
return this
}
/**
* Determine if blocked.
* Prevents stacking polls if there is some external slowness
*
* @method isBlocked
* @return {boolean} True if blocked, False otherwise.
*/
get isBlocked () {
return this._blocked || false
}
/**
* Toggles if we should block on the next polling cycle
*
* @method toggleBlocked
*/
toggleBlocked () {
this._blocked = this._blocked ? false : true
return this
}
/**
* kills the Loop
*
* @method kill
*/
kill () {
this.pause()
this.removeAllListeners()
}
/**
* Main polling loop handler
*
* @method tick
*/
tick () {
// Prevent stacking operations if RethinkDB cluster is under stress
if ( this.isBlocked ) return
this.toggleBlocked()
this.emitTick((function unblock () {
this.toggleBlocked()
}).bind(this))
}
}
Loop.Event = {
down : 'loop:down'
, up : 'loop:up'
, tick : 'loop:tick'
}
Events.methodize( Loop, Loop.Event )