Skip to content

Commit

Permalink
Add a cooldownInterval options
Browse files Browse the repository at this point in the history
When monitoring a script, it's handy to limit the maximum number of
restart. But it's not the same if the script fails 10 times in 10
seconds and 10 times in 10 weeks. On the first case, there is probably
an hard error and it's better to stop soon trying to restart this
script. But on the second case, a max of 10 is not enough. Maybe it's
just a crontab running once a week that makes it fail.

The cooldownInterval is here to make max time sensitive. Forever-monitor
keeps a counter with the number of failures of the script. When this
counter reaches the max, it stops trying to restart it. With
cooldownInterval, this counter is halfed at a regular interval defined
by the number of seconds of cooldownInterval.

For example, with cooldownInterval=300, if the counter is at 4 failures
and in the next 5 minutes, the script won't fail, it will go to 2. And
if the next 5 following minutes, it still run quiet, it will go to 1.
And 5 more minutes, and will be reset to 0.
  • Loading branch information
nono committed Feb 10, 2016
1 parent e2cfd05 commit 9a2e9fd
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ There are several options that you should be aware of when using forever. Most o
'uid': 'your-UID', // Custom uid for this forever process. (default: autogen)
'pidFile': 'path/to/a.pid', // Path to put pid information for the process(es) started
'max': 10, // Sets the maximum number of times a given script should run
'cooldownInterval': 300, // Stop restarting if max is reached during this interval (in seconds)
'killTree': true, // Kills the entire child process tree on `exit`

//
Expand Down
4 changes: 4 additions & 0 deletions lib/forever-monitor/monitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ var Monitor = exports.Monitor = function (script, options) {
if (options.watch) {
plugins.watch.attach.call(monitor, options);
}
if (options.cooldownInterval) {
plugins.cooldown.attach.call(monitor, options);
}
}

var execPath = process.execPath,
Expand All @@ -50,6 +53,7 @@ var Monitor = exports.Monitor = function (script, options) {
this.id = options.id || false;
this.pidFile = options.pidFile;
this.max = options.max;
this.cooldownInterval = options.cooldownInterval || null;
this.killTTL = options.killTTL;
this.killSignal = options.killSignal || 'SIGKILL';
this.childExists = false;
Expand Down
28 changes: 28 additions & 0 deletions lib/forever-monitor/plugins/cooldown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* watch.js: Plugin for `Monitor` instances which decreases the count of
* failures over time. It makes the max option time sensitive (ie it's not the
* same to have 10 failures in 10 seconds and 10 failures in 10 weeks).
*
* (C) 2010 Charlie Robbins & the Contributors
* MIT LICENCE
*
*/

//
// Name the plugin
//
exports.name = 'cooldown';

//
// ### function attach (options)
// #### @options {Object} Options for attaching to `Monitor`
//
// Attaches functionality for logging stdout and stderr to `Monitor` instances.
//
exports.attach = function (options) {
var monitor = this;

setInterval(function() {
monitor.times = Math.floor(monitor.times / 2);
}, options.cooldownInterval * 1000);
}
5 changes: 3 additions & 2 deletions lib/forever-monitor/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
*
*/

exports.logger = require('./logger');
exports.watch = require('./watch');
exports.logger = require('./logger');
exports.watch = require('./watch');
exports.cooldown = require('./cooldown')
43 changes: 43 additions & 0 deletions test/plugins/cooldown-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
var assert = require('assert')
path = require('path'),
vows = require('vows'),
fmonitor = require('../../lib'),
macros = require('../helpers/macros');

var examplesDir = path.join(__dirname, '..', '..', 'examples');

vows.describe('forever-monitor/plugins/logger').addBatch({
'When using the cooldown plugin': {
'running error-on-timer sample one hundred times': {
topic: function () {
var script = path.join(examplesDir, 'error-on-timer.js');
var options = {
max: 10,
cooldownInterval: 1,
silent: true,
outFile: 'test/fixtures/stdout.log',
errFile: 'test/fixtures/stderr.log',
args: []
}
var child = new (fmonitor.Monitor)(script, options);
setTimeout(this.callback.bind({}, null, child), 2100);
child.start();
},
'should have not reached max': function (err, child) {
assert.ok(child.times < 10);
}
},
'running error-on-timer sample three times': macros.assertTimes(
path.join(examplesDir, 'error-on-timer.js'),
3,
{
cooldownInterval: 10,
minUptime: 200,
silent: true,
outFile: 'test/fixtures/stdout.log',
errFile: 'test/fixtures/stderr.log',
args: []
}
)
}
}).export(module);

0 comments on commit 9a2e9fd

Please sign in to comment.