@atomist/automation-client
Version:
Atomist API for software low-level client
166 lines • 6.12 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const stringify = require("json-stringify-safe");
const ApolloGraphClientFactory_1 = require("../../../graph/ApolloGraphClientFactory");
const AutomationEventListener_1 = require("../../../server/AutomationEventListener");
const MessageClientSupport_1 = require("../../../spi/message/MessageClientSupport");
const Deferred_1 = require("../../util/Deferred");
const logger_1 = require("../../util/logger");
const memory_1 = require("../../util/memory");
const shutdown_1 = require("../../util/shutdown");
const string_1 = require("../../util/string");
const AbstractRequestProcessor_1 = require("../AbstractRequestProcessor");
const messages_1 = require("./messages");
/**
* A RequestProcessor that is being run as Node.JS Cluster worker handling all the actual work.
*/
class ClusterWorkerRequestProcessor extends AbstractRequestProcessor_1.AbstractRequestProcessor {
/* tslint:disable:variable-name */
constructor(_automations, _configuration, _listeners = []) {
super(_automations, _configuration, [..._listeners, new ClusterWorkerAutomationEventListener()]);
this._automations = _automations;
this._configuration = _configuration;
this._listeners = _listeners;
messages_1.workerSend({ type: "online", context: null });
shutdown_1.registerShutdownHook(() => {
if (this._configuration.ws &&
this._configuration.ws.termination &&
this._configuration.ws.termination.graceful === true) {
logger_1.logger.info("Initiating worker shutdown");
// Now wait for configured timeout to let in-flight messages finish processing
const deferred = new Deferred_1.Deferred();
setTimeout(() => {
logger_1.logger.info("Shutting down worker");
deferred.resolve(0);
}, this._configuration.ws.termination.gracePeriod + 2500);
return deferred.promise
.then(code => {
return code;
});
}
else {
logger_1.logger.info("Shutting down worker");
return Promise.resolve(0);
}
});
}
/* tslint:enable:variable-name */
setRegistration(registration) {
logger_1.logger.debug("Receiving registration '%s'", stringify(registration));
this.registration = registration;
this.graphClients =
new ApolloGraphClientFactory_1.ApolloGraphClientFactory(this._configuration, () => `Bearer ${registration.jwt}`);
}
setRegistrationIfRequired(data) {
if (!this.registration) {
this.setRegistration(data.registration);
}
}
sendStatusMessage(payload, ctx) {
return messages_1.workerSend({
type: "status",
context: ctx.context,
data: payload,
});
}
createGraphClient(event, context) {
return this.graphClients.createGraphClient(event);
}
createMessageClient(event, context) {
return new ClusterWorkerMessageClient(event, context);
}
setupNamespace(request, automations, invocationId = string_1.guid(), ts = Date.now()) {
const context = request.__context;
delete request.__context;
return context;
}
}
exports.ClusterWorkerRequestProcessor = ClusterWorkerRequestProcessor;
class ClusterWorkerMessageClient extends MessageClientSupport_1.MessageClientSupport {
constructor(event, ctx) {
super();
this.event = event;
this.ctx = ctx;
}
doSend(msg, destinations, options) {
return messages_1.workerSend({
type: "message",
context: this.ctx.context,
data: {
message: msg,
destinations,
options,
},
});
}
}
class ClusterWorkerAutomationEventListener extends AutomationEventListener_1.AutomationEventListenerSupport {
commandSuccessful(payload, ctx, result) {
return messages_1.workerSend({
type: "command_success",
event: payload,
context: ctx.context,
data: result,
});
}
commandFailed(payload, ctx, err) {
return messages_1.workerSend({
type: "command_failure",
event: payload,
context: ctx.context,
data: err,
});
}
eventSuccessful(payload, ctx, result) {
return messages_1.workerSend({
type: "event_success",
event: payload,
context: ctx.context,
data: result,
});
}
eventFailed(payload, ctx, err) {
return messages_1.workerSend({
type: "event_failure",
event: payload,
context: ctx.context,
data: err,
});
}
}
/**
* Start a new worker node
* @param {AutomationServer} automations
* @param {WebSocketClientOptions} options
* @returns {RequestProcessor}
*/
function startWorker(automations, configuration, listeners = []) {
const worker = new ClusterWorkerRequestProcessor(automations, configuration, listeners);
process.on("message", msg => {
if (msg.type === "registration") {
worker.setRegistration(msg.registration);
}
else if (msg.type === "command") {
worker.setRegistrationIfRequired(msg);
worker.processCommand(decorateContext(msg));
}
else if (msg.type === "event") {
worker.setRegistrationIfRequired(msg);
worker.processEvent(decorateContext(msg));
}
else if (msg.type === "gc") {
memory_1.gc();
}
else if (msg.type === "heapdump") {
memory_1.heapDump();
}
});
return worker;
}
exports.startWorker = startWorker;
function decorateContext(msg) {
const event = msg.data;
event.__context = msg.context;
return event;
}
//# sourceMappingURL=ClusterWorkerRequestProcessor.js.map