testarmada-magellan
Version:
Massively parallel automated testing
73 lines (61 loc) • 2.12 kB
JavaScript
/* eslint operator-assignment: 0 */
;
const settings = require("../settings");
const checkPorts = require("./check_ports");
const MAX_ACQUIRE_ATTEMPTS = 100;
const MAX_PORT = settings.BASE_PORT_START + settings.BASE_PORT_RANGE - 1;
let portCursor;
const util = {
// Return magellan's internal port cursor, i.e. the next port that can potentially
// be probed for availability. This doesn't perform a port contention check. Calling
// this function also ticks the port cursor upwards regardless of result.
getNextPort: () => {
// Reset back to start of range
if (typeof portCursor === "undefined" || portCursor + settings.BASE_PORT_SPACING > MAX_PORT) {
portCursor = settings.BASE_PORT_START;
}
// Choose the next port
const nextPort = portCursor;
// Allocate the port for the next worker -- or spill over the range
portCursor = portCursor + settings.BASE_PORT_SPACING;
return nextPort;
},
// Call callback(err, foundPort) with either:
//
// 1) an Error object, if we couldnt' find a port
// 2) null and a foundPort as the second argument
acquirePort: (callback) => {
let attempts = 0;
const acquire = () => {
// check all the ports in the range. If fail, move to next set
const startPort = util.getNextPort();
const ports = [];
for (let i = startPort; i < startPort + settings.BASE_PORT_SPACING; i++) {
ports.push(i);
}
checkPorts(ports, (result) => {
let available = true;
for (let i = 0; i < result.length; i++) {
if (!result[i].available) {
available = false;
break;
}
}
if (available) {
return callback(null, result[0].port);
} else {
attempts++;
if (attempts > MAX_ACQUIRE_ATTEMPTS) {
return callback(new Error("Gave up looking for an available port after "
+ MAX_ACQUIRE_ATTEMPTS + " attempts."));
} else {
acquire();
}
}
});
};
acquire();
},
checkPorts
};
module.exports = util;