forked from karma-runner/karma-browserstack-launcher
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Global poller for updating worker status
Uses a shared poller to fetch and update the status of workers; helps reduce the no. of requests made to BrowserStack. Ref karma-runner#30
- Loading branch information
Showing
2 changed files
with
198 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
'use strict'; | ||
|
||
var EventEmitter = require('events').EventEmitter; | ||
var util = require('util'); | ||
|
||
|
||
function Worker(data) { | ||
EventEmitter.call(this); | ||
|
||
if (typeof data === 'object' && !Array.isArray(data)) { | ||
var self = this; | ||
|
||
Object.keys(data).forEach(function (k) { | ||
self[k] = data[k]; | ||
}); | ||
} | ||
} | ||
|
||
util.inherits(Worker, EventEmitter); | ||
|
||
|
||
/** | ||
* Tracks worker state across runs. | ||
*/ | ||
function WorkerManager() { | ||
this._pollHandle = null; | ||
|
||
this.workers = {}; | ||
this.isPolling = false; | ||
} | ||
|
||
|
||
WorkerManager.prototype.registerWorker = function registerWorker(workerData) { | ||
if (this.workers[workerData.id]) { | ||
this.unregisterWorker(this.workers[workerData.id]); | ||
} | ||
|
||
var worker = new Worker(workerData); | ||
worker.emit('status', worker.status); | ||
|
||
this.workers[workerData.id] = worker; | ||
return worker; | ||
}; | ||
|
||
|
||
WorkerManager.prototype.unregisterWorker = function unregisterWorker(worker) { | ||
worker.emit('delete', worker); | ||
worker.removeAllListeners(); | ||
|
||
delete this.workers[worker.id]; | ||
return worker; | ||
}; | ||
|
||
|
||
WorkerManager.prototype.updateWorker = function updateWorker(workerData) { | ||
var workers = this.workers; | ||
|
||
if (workers[workerData.id]) { | ||
var worker = workers[workerData.id]; | ||
var prevStatus = worker.status; | ||
|
||
Object.keys(workerData).forEach(function (k) { | ||
worker[k] = workerData[k]; | ||
}); | ||
|
||
if (worker.status !== prevStatus) { | ||
worker.emit('status', worker.status); | ||
} | ||
|
||
return worker; | ||
} | ||
|
||
// will end up including workers that don't belong to current run | ||
// return WorkerManager.registerWorker(workerData); | ||
}; | ||
|
||
|
||
WorkerManager.prototype.startPolling = function startPolling(client, pollingTimeout, callback) { | ||
if (this.isPolling) { | ||
return; | ||
} | ||
|
||
var self = this; | ||
this.isPolling = true; | ||
|
||
client.getWorkers(function (err, updatedWorkers) { | ||
if (err) { | ||
self.isPolling = false; | ||
return (callback ? callback(err) : null); | ||
} | ||
|
||
updatedWorkers = updatedWorkers || []; | ||
var activeWorkerIds = updatedWorkers.map(function (worker) { | ||
return worker.id; | ||
}); | ||
|
||
// process deletions | ||
for (var i = 0, l = self.workers.length; i < l; i++) { | ||
var worker = self.workers[i]; | ||
if (activeWorkerIds.indexOf(worker.id) === -1) { | ||
self.unregisterWorker(worker); | ||
} | ||
} | ||
|
||
// process updates | ||
var existingWorkerIds = Object.keys(self.workers); | ||
updatedWorkers.forEach(function (workerData) { | ||
self.updateWorker(workerData); | ||
}); | ||
|
||
self._pollHandle = setTimeout(function () { | ||
self.isPolling = false; | ||
self.startPolling(client, pollingTimeout, callback); | ||
}, pollingTimeout); | ||
|
||
}); | ||
}; | ||
|
||
|
||
WorkerManager.prototype.stopPolling = function stopPolling() { | ||
if (this._pollHandle) { | ||
clearTimeout(this._pollHandle); | ||
this._pollHandle = null; | ||
} | ||
|
||
this.isPolling = false; | ||
}; | ||
|
||
|
||
// expose a single, shared instance of WorkerManager | ||
var workerManager = new WorkerManager(); | ||
|
||
module.exports = { | ||
Worker: Worker, | ||
|
||
WorkerManager: { | ||
getInstance: function () { | ||
return workerManager; | ||
} | ||
} | ||
}; |