Skip to content

Commit

Permalink
ready for 0.8 upgrade lifecycle helper
Browse files Browse the repository at this point in the history
  • Loading branch information
nullivex committed Sep 29, 2014
1 parent ec62ce2 commit 78eb9a7
Show file tree
Hide file tree
Showing 4 changed files with 235 additions and 23 deletions.
29 changes: 25 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -431,14 +431,15 @@ are from the previous workers exit

Takes no arguments, returns a new lifecycle instance

#### Lifecycle.prototype.add(start,stop)
#### Lifecycle.prototype.add(title,start,stop)

Title is a string that will be provided during events

Where start and stop are functions that are passed a `done(err)` callback

#### Lifecycle.prototype.remove(start,stop)
#### Lifecycle.prototype.remove(title)

Remove the member from the lifecycle, using the original start and stop
functions to identify the member.
Remove the member from the lifecycle, using the title to identify the member

#### Lifecycle.prototype.start(done)

Expand All @@ -450,8 +451,28 @@ when complete.
Will stop all the members in reverse order that they were added and call
`done(err)` when complete.

#### Lifecycle Events

* `add` - Emitted when a member is added, args: `item` the item being
added
* `remove` - Emitted when a member is removed, args: `item` the item being
removed
* `start` - Emitted when a member is started, args: `item` the item being
started
* `stop` - Emitted when a member is stopped, args: `item` the item being
stopped
* `online` - Emitted when the startup sequence is complete
* `offline` - Emitted when the shutdown sequence is complete

## Changelog

### 0.8.0
* Lifecycle helper now takes an optional name
* Lifecycle helper is now an event emitter (useful for loggin)
* Added tests against the Lifecycle helper
* There is a breaking change to the lifecycle helper, where removals require
the title to be specified

### 0.7.0
* Improved worker setup helper to include graceful startup and shutdown
* Child.fork now supports timeouts on runOnce processes
Expand Down
91 changes: 73 additions & 18 deletions helpers/Lifecycle.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
'use strict';
var async = require('async')
var EventEmitter = require('events').EventEmitter

var nullFunc = function(done){done()}



Expand All @@ -11,32 +14,62 @@ var async = require('async')
* @constructor
*/
var Lifecycle = function(){
this._start = []
this._stop = []
EventEmitter.call(this)
this.items = []
}
Lifecycle.prototype = Object.create(EventEmitter.prototype)


/**
* Get the next index
* @return {Number}
*/
Lifecycle.prototype.nextIndex = function(){
return this.items.length
}


/**
* Add a new sequence
* @param {string} title
* @param {function} start
* @param {function} stop
* @return {object} item
*/
Lifecycle.prototype.add = function(start,stop){
if(start && 'function' === typeof start) this._start.push(start)
if(stop && 'function' === typeof stop) this._stop.unshift(stop)
Lifecycle.prototype.add = function(title,start,stop){
if('function' === typeof title){
start = title
stop = start
title = this.nextIndex()
}
var item = {
index: this.nextIndex(),
title: title,
start: start || nullFunc,
stop: stop || nullFunc
}
this.emit('add',item)
this.items.push(item)
return item
}


/**
* Remove a sequence from the stack
* @param {function} start
* @param {function} stop
* @param {string} title
* @return {object} item
*/
Lifecycle.prototype.remove = function(start,stop){
if(start && 'function' === typeof start)
this._start.splice(this._start.indexOf(start),1)
if(stop && 'function' === typeof stop)
this._stop.splice(this._start.indexOf(stop),1)
Lifecycle.prototype.remove = function(title){
var that = this
var item = null
//remove the item
that.items.forEach(function(v,i){
if(title === v.title){
item = that.items.splice(i,1)[0]
that.emit('remove',item)
}
})
return item
}


Expand All @@ -45,10 +78,21 @@ Lifecycle.prototype.remove = function(start,stop){
* @param {function} done
*/
Lifecycle.prototype.start = function(done){
var that = this
//sort into start order
that.items = that.items.sort(function(a,b){return a.index - b.index})
//start items
async.eachSeries(
this._start,
function(item,next){item(next)},
done
that.items,
function(item,next){
that.emit('start',item)
item.start(next)
},
function(err){
if(err) return done(err)
that.emit('online')
done()
}
)
}

Expand All @@ -58,10 +102,21 @@ Lifecycle.prototype.start = function(done){
* @param {function} done
*/
Lifecycle.prototype.stop = function(done){
var that = this
//sort into stop order
that.items = that.items.sort(function(a,b){return b.index - a.index})
//stop items
async.eachSeries(
this._stop,
function(item,next){item(next)},
done
that.items,
function(item,next){
that.emit('stop',item)
item.stop(next)
},
function(err){
if(err) return done(err)
that.emit('offline')
done()
}
)
}

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"author": "SnailJS <developers@snailjs.org>",
"name": "infant",
"description": "Child process, and cluster helper for Node.js",
"version": "0.7.0",
"version": "0.8.0",
"homepage": "http://snailjs.org/",
"repository": {
"type": "git",
Expand Down Expand Up @@ -31,6 +31,7 @@
"test": "node ./node_modules/mocha/bin/mocha"
},
"devDependencies": {
"async": "0.9.x",
"chai": "1.9.x",
"mocha": "1.21.x",
"request": "2.44.x"
Expand Down
135 changes: 135 additions & 0 deletions test/Lifecycle.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
'use strict';
var expect = require('chai').expect

var Lifecycle = require('../helpers/Lifecycle')


describe('helpers/Lifecycle',function(){
var inst
beforeEach(function(done){
inst = new Lifecycle()
done()
})
afterEach(function(done){
inst = null
done()
})
it('should allow adding of sequences',function(done){
inst.add('test')
expect(inst.items[0].title).to.equal('test')
done()
})
it('should allow adding of sequences without title',function(done){
inst.add(function(next){
expect(next).to.be.a('function')
next()
})
inst.start(done)
})
it('should allow removing of sequences',function(done){
inst.add('test')
var item = inst.remove('test')
expect(item.title).to.equal('test')
expect(inst.items[0]).to.equal(undefined)
done()
})
it('should start in order',function(done){
inst.add('test1')
inst.add('test2')
inst.once('start',function(item){
expect(item.title).to.equal('test1')
inst.once('start',function(item){
expect(item.title).to.equal('test2')
})
})
inst.start(done)
})
it('should stop in order',function(done){
inst.add('test1')
inst.add('test2')
inst.once('stop',function(item){
expect(item.title).to.equal('test2')
inst.once('stop',function(item){
expect(item.title).to.equal('test1')
})
})
inst.stop(done)
})
it('should call callbacks during start',function(done){
inst.add('test1',function(next){
expect(next).to.be.a('function')
next()
})
inst.start(done)
})
it('should call callbacks during stop',function(done){
inst.add('test2',function(next){
expect(next).to.be.a('function')
next()
})
inst.stop(done)
})
it('should bubble errors on start',function(done){
inst.add('test1',function(next){
next('foo')
})
inst.start(function(err){
expect(err).to.equal('foo')
done()
})
})
it('should bubble errors on stop',function(done){
inst.add('test1',null,function(next){
next('foo')
})
inst.stop(function(err){
expect(err).to.equal('foo')
done()
})
})
it('should emit a start event',function(done){
inst.add('test1')
inst.once('start',function(item){
expect(item.title).to.equal('test1')
done()
})
inst.start(function(err){if(err) done(err)})
})
it('should emit a stop event',function(done){
inst.add('test1')
inst.once('stop',function(item){
expect(item.title).to.equal('test1')
done()
})
inst.stop(function(err){if(err) done(err)})
})
it('should emit an online event',function(done){
inst.add('test1')
inst.once('online',function(){
done()
})
inst.start(function(err){if(err) done(err)})
})
it('should emit an offline event',function(done){
inst.add('test1')
inst.once('offline',function(){
done()
})
inst.stop(function(err){if(err) done(err)})
})
it('should emit an add event',function(done){
inst.once('add',function(item){
expect(item.title).to.equal('test1')
done()
})
inst.add('test1')
})
it('should emit a remove event',function(done){
inst.once('remove',function(item){
expect(item.title).to.equal('test1')
done()
})
inst.add('test1')
inst.remove('test1')
})
})

0 comments on commit 78eb9a7

Please sign in to comment.