Permalink
Browse files

Set timeouts per batch, enforce timeouts.

Accept a `timeout` option in createBatch
and a `--timeout` option on the command line
to specify an agent timeout in seconds.

No longer use a `waiting` flag for agents on the
capture page. Instead, the capture page now checks
in with the Hub every 10 seconds which resets the
server-side agent timeout.

Change the server-side agent timeout to 45 seconds,
up from 3.6 seconds.
  • Loading branch information...
1 parent 1c358bd commit 08e8940e20d66d89cd887e634312c99a279d978a @reid reid committed Aug 24, 2012
Showing with 58 additions and 12 deletions.
  1. +2 −0 lib/cli.js
  2. +2 −0 lib/client.js
  3. +43 −11 lib/hub/agent.js
  4. +3 −0 lib/hub/batch.js
  5. +8 −1 lib/hub/view/public/capture.js
View
@@ -67,6 +67,7 @@ function parseArgv(argv) {
"query": String,
"debug": Boolean,
"port": Number,
+ "timeout": Number,
"hub": String,
"help" : Boolean
}, shortHands = {
@@ -282,6 +283,7 @@ function runBatch(options) {
batchOptions = {
basedir: process.cwd(),
query: query,
+ timeout: options.timeout,
tests: files
};
View
@@ -268,6 +268,8 @@ Client.prototype.handleBlizzardError = function (err) {
* @param {String[]} config.tests Tests. Either relative paths to `config.basedir` or URL pathnames.
* @param {String} [config.basedir] Root path for serving tests. Required if `useProxy` is true or not provided.
* @param {String} [config.query] Query string additions for test URLs.
+ * @param {Number} [config.timeout] Per-test timeout in seconds. Default is 45 seconds.
+ * If no activity occurs before the timeout, the next test is loaded.
* @param {Boolean} [config.useProxy] True if tests are filenames to proxy to the Hub.
* false if they are literal URL pathnames.
* If not provided, defaults to true.
View
@@ -51,7 +51,6 @@ function Agent(manager, registration) {
this.name = parseUA(this.ua);
this.seen = new Date();
- this.waiting = true;
this.connected = true;
this.dispatchedTests = 0;
@@ -70,6 +69,8 @@ function Agent(manager, registration) {
this.socketEmitter = new EventYoshi();
this.socketEmitterQueue = [];
+ this.defaults = {};
+
this.setupEvents();
if (abortNow) {
@@ -81,16 +82,16 @@ function Agent(manager, registration) {
util.inherits(Agent, EventEmitter2);
/**
- * TTL for Agents in seconds.
+ * TTL for Agents in milliseconds.
*
* Agents are discared if they do not respond
- * for this many seconds.
+ * for this many milliseconds.
*
* @property TTL
* @type Number
- * @default 3600
+ * @default 45000
*/
-Agent.TTL = 3600;
+Agent.TTL = 45000;
/**
* The Agent emitted a heartbeat.
@@ -140,6 +141,36 @@ Agent.TTL = 3600;
*/
/**
+ * Set a new TTL.
+ * The old TTL will be restored when the complete event fires.
+ *
+ * @method setTTLUntilComplete
+ * @param {Number} ttl TTL in milliseconds.
+ */
+Agent.prototype.setTTLUntilComplete = function (ttl) {
+ this.debug("setTTLUntilComplete:", ttl);
+ this.defaults.ttl = this.ttl;
+ this.ttl = ttl;
+};
+
+/**
+ * Restore default settings.
+ *
+ * @method restoreDefaults
+ * @private
+ */
+Agent.prototype.restoreDefaults = function () {
+ var self = this;
+ Object.keys(self.defaults).forEach(function (name) {
+ if (name in self) {
+ self.debug("restoreDefaults restored", name, "to", self.defaults[name]);
+ self[name] = self.defaults[name];
+ delete self.defaults[name];
+ }
+ });
+};
+
+/**
* Setup events on `this.socketEmitter`.
*
* @method setupEvents
@@ -230,7 +261,6 @@ Agent.prototype.nextURL = function () {
if (this.urlQueue.length) {
url = this.urlQueue.shift();
- this.waiting = false;
this.emit("progress", {
total: this.dispatchedTests,
current: this.dispatchedTests - this.urlQueue.length
@@ -243,8 +273,8 @@ Agent.prototype.nextURL = function () {
}
url += "agent/" + this.id;
- this.waiting = true;
this.emit("complete");
+ this.restoreDefaults();
}
this.currentUrl = url;
@@ -290,7 +320,7 @@ Agent.prototype.next = function () {
* @return {Boolean} True if the browser idle, false if it is running tests.
*/
Agent.prototype.available = function () {
- return this.waiting;
+ return !this.urlQueue.length;
};
/**
@@ -320,7 +350,6 @@ Agent.prototype.unload = function () {
this.debug("disconnecting agent! stack:", (new Error()).stack);
this.connected = false;
this.seen = 0;
- this.waiting = false;
this.emit("disconnect");
};
@@ -359,7 +388,10 @@ Agent.prototype.ping = function () {
* @return {Boolean} True if the Agent is expired, false otherwise.
*/
Agent.prototype.expired = function () {
- return (!this.waiting && ((Date.now() - this.seen) > this.ttl));
+ var age = Date.now() - this.seen,
+ ttl = this.ttl;
+ this.debug("expired check, age:", age, "ttl:", ttl);
+ return age > ttl;
};
/**
@@ -408,7 +440,7 @@ util.inherits(AgentManager, EventEmitter2);
*/
//TODO Make this configurable
//TODO This should probably be allowed to be passed to an Agent as it's TTL too. Not sure
-AgentManager.REAP_TTL = (45 * 1000); //Default reap timeout
+AgentManager.REAP_TTL = (10 * 1000); //Default reap timeout
/**
* TODO
View
@@ -22,6 +22,7 @@ function Batch(manager, id, session, options) {
this.session = session;
this.tests = options.tests;
this.query = options.query;
+ this.timeout = options.timeout;
this.useProxy = options.useProxy;
this.agentManager = manager.agentManager;
@@ -191,6 +192,8 @@ Batch.prototype.dispatch = function () {
urls = self.tests.slice();
}
+ agent.setTTLUntilComplete(self.timeout * 1000);
+
agent.dispatch(urls);
});
@@ -14,7 +14,8 @@
].join("");
}
- var reconnectInterval = 1;
+ var reconnectInterval = 1,
+ beatInterval;
window.Yeti = {
capture: function capture(resource) {
@@ -43,6 +44,10 @@
}
};
+ function beat() {
+ tower.emit("beat");
+ }
+
tower.queueUntil("listening");
tower.on("listening", function () {
if (reconnectInterval > 2) {
@@ -58,6 +63,7 @@
document.getElementById("test").innerHTML = "Sending registration...";
});
tower.on("ready", function (id) {
+ beatInterval = window.setInterval(beat, 10000);
// Only matters when we fully reconnect
// without a reload, but for completeness:
reconnectInterval = 1;
@@ -71,6 +77,7 @@
document.location.href = test;
});
tower.on("close", function () {
+ window.clearInterval(beatInterval);
var seconds = reconnectInterval;
(function tick() {
document.getElementById("test").innerHTML = "Disconnected, " +

0 comments on commit 08e8940

Please sign in to comment.