teraslice 0.87.0 → 0.88.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cluster-service.js +24 -18
- package/dist/src/index.js +42 -0
- package/package.json +11 -15
- package/service.js +4 -6
- package/worker-service.js +6 -6
- package/index.js +0 -21
- package/lib/cluster/cluster_master.js +0 -164
- package/lib/cluster/node_master.js +0 -393
- package/lib/cluster/services/api.js +0 -581
- package/lib/cluster/services/assets.js +0 -211
- package/lib/cluster/services/cluster/backends/kubernetes/deployments/worker.hbs +0 -86
- package/lib/cluster/services/cluster/backends/kubernetes/index.js +0 -225
- package/lib/cluster/services/cluster/backends/kubernetes/jobs/execution_controller.hbs +0 -69
- package/lib/cluster/services/cluster/backends/kubernetes/k8s.js +0 -450
- package/lib/cluster/services/cluster/backends/kubernetes/k8sResource.js +0 -443
- package/lib/cluster/services/cluster/backends/kubernetes/k8sState.js +0 -67
- package/lib/cluster/services/cluster/backends/kubernetes/utils.js +0 -58
- package/lib/cluster/services/cluster/backends/native/index.js +0 -611
- package/lib/cluster/services/cluster/backends/native/messaging.js +0 -563
- package/lib/cluster/services/cluster/backends/state-utils.js +0 -49
- package/lib/cluster/services/cluster/index.js +0 -15
- package/lib/cluster/services/execution.js +0 -459
- package/lib/cluster/services/jobs.js +0 -303
- package/lib/config/default-sysconfig.js +0 -47
- package/lib/config/index.js +0 -32
- package/lib/config/schemas/system.js +0 -333
- package/lib/processors/save_file/index.js +0 -9
- package/lib/processors/save_file/processor.js +0 -17
- package/lib/processors/save_file/schema.js +0 -17
- package/lib/processors/script.js +0 -130
- package/lib/processors/stdout/index.js +0 -9
- package/lib/processors/stdout/processor.js +0 -19
- package/lib/processors/stdout/schema.js +0 -18
- package/lib/storage/analytics.js +0 -106
- package/lib/storage/assets.js +0 -275
- package/lib/storage/backends/elasticsearch_store.js +0 -567
- package/lib/storage/backends/mappings/analytics.json +0 -49
- package/lib/storage/backends/mappings/asset.json +0 -40
- package/lib/storage/backends/mappings/ex.json +0 -55
- package/lib/storage/backends/mappings/job.json +0 -31
- package/lib/storage/backends/mappings/state.json +0 -37
- package/lib/storage/execution.js +0 -331
- package/lib/storage/index.js +0 -16
- package/lib/storage/jobs.js +0 -97
- package/lib/storage/state.js +0 -302
- package/lib/utils/api_utils.js +0 -173
- package/lib/utils/asset_utils.js +0 -117
- package/lib/utils/date_utils.js +0 -58
- package/lib/utils/encoding_utils.js +0 -29
- package/lib/utils/events.js +0 -7
- package/lib/utils/file_utils.js +0 -118
- package/lib/utils/id_utils.js +0 -19
- package/lib/utils/port_utils.js +0 -83
- package/lib/workers/assets/loader.js +0 -109
- package/lib/workers/assets/spawn.js +0 -78
- package/lib/workers/context/execution-context.js +0 -16
- package/lib/workers/context/terafoundation-context.js +0 -10
- package/lib/workers/execution-controller/execution-analytics.js +0 -211
- package/lib/workers/execution-controller/index.js +0 -1033
- package/lib/workers/execution-controller/recovery.js +0 -188
- package/lib/workers/execution-controller/scheduler.js +0 -461
- package/lib/workers/execution-controller/slice-analytics.js +0 -115
- package/lib/workers/helpers/job.js +0 -93
- package/lib/workers/helpers/op-analytics.js +0 -22
- package/lib/workers/helpers/terafoundation.js +0 -43
- package/lib/workers/helpers/worker-shutdown.js +0 -187
- package/lib/workers/metrics/index.js +0 -139
- package/lib/workers/worker/index.js +0 -344
- package/lib/workers/worker/slice.js +0 -143
|
@@ -1,563 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const _ = require('lodash');
|
|
4
|
-
const { nanoid } = require('nanoid');
|
|
5
|
-
const { pDelay, Queue } = require('@terascope/utils');
|
|
6
|
-
|
|
7
|
-
// messages send to cluster_master
|
|
8
|
-
const clusterMasterMessages = {
|
|
9
|
-
ipc: {
|
|
10
|
-
'process:SIGTERM': 'SIGTERM',
|
|
11
|
-
'process:SIGINT': 'SIGINT',
|
|
12
|
-
},
|
|
13
|
-
intraProcess: {
|
|
14
|
-
'network:disconnect': 'disconnect',
|
|
15
|
-
'network:error': 'error',
|
|
16
|
-
},
|
|
17
|
-
network: {
|
|
18
|
-
'node:online': 'node:online',
|
|
19
|
-
'node:state': 'node:state',
|
|
20
|
-
'execution:recovery:failed': 'execution:recovery:failed',
|
|
21
|
-
'execution:finished': 'execution:finished',
|
|
22
|
-
'cluster:analytics': 'cluster:analytics',
|
|
23
|
-
'execution:error:terminal': 'execution:error:terminal',
|
|
24
|
-
'assets:preloaded': 'assets:preloaded',
|
|
25
|
-
'assets:service:available': 'assets:service:available'
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const nodeMasterMessages = {
|
|
30
|
-
ipc: {
|
|
31
|
-
'cluster:error:terminal': 'cluster:error:terminal',
|
|
32
|
-
'child:exit': 'exit'
|
|
33
|
-
},
|
|
34
|
-
intraProcess: {
|
|
35
|
-
'network:connect': 'connect',
|
|
36
|
-
'network:disconnect': 'disconnect',
|
|
37
|
-
'network:error': 'error',
|
|
38
|
-
},
|
|
39
|
-
network: {
|
|
40
|
-
'cluster:execution_controller:create': 'cluster:execution_controller:create',
|
|
41
|
-
'cluster:workers:create': 'cluster:workers:create',
|
|
42
|
-
'cluster:workers:remove': 'cluster:workers:remove',
|
|
43
|
-
'cluster:node:state': 'cluster:node:state',
|
|
44
|
-
'cluster:execution:stop': 'cluster:execution:stop',
|
|
45
|
-
'cluster:node:get_port': 'cluster:node:get_port',
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const assetServiceMessages = {
|
|
50
|
-
ipc: {
|
|
51
|
-
'process:SIGTERM': 'SIGTERM',
|
|
52
|
-
'process:SIGINT': 'SIGINT',
|
|
53
|
-
},
|
|
54
|
-
network: {}
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
// messaging destination relative towards each process type
|
|
58
|
-
const routing = {
|
|
59
|
-
cluster_master: {
|
|
60
|
-
node_master: 'network',
|
|
61
|
-
},
|
|
62
|
-
node_master: {
|
|
63
|
-
cluster_process: 'ipc',
|
|
64
|
-
cluster_master: 'network',
|
|
65
|
-
},
|
|
66
|
-
assets_service: {
|
|
67
|
-
cluster_master: 'ipc'
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
module.exports = function messaging(context, logger) {
|
|
72
|
-
const functionMapping = {};
|
|
73
|
-
// processContext is set in _makeConfigurations
|
|
74
|
-
let processContext;
|
|
75
|
-
const config = _makeConfigurations();
|
|
76
|
-
const { hostURL } = config;
|
|
77
|
-
const configTimeout = context.sysconfig.teraslice.action_timeout;
|
|
78
|
-
const networkLatencyBuffer = context.sysconfig.teraslice.network_latency_buffer;
|
|
79
|
-
const self = config.assignment;
|
|
80
|
-
const events = context.apis.foundation.getSystemEvents();
|
|
81
|
-
const selfMessages = _getMessages(self);
|
|
82
|
-
const messagingQueue = new Queue();
|
|
83
|
-
|
|
84
|
-
let messsagingOnline = false;
|
|
85
|
-
let childHookFn = null;
|
|
86
|
-
let io;
|
|
87
|
-
|
|
88
|
-
logger.debug(`messaging service configuration for assignment ${config.assignment}`);
|
|
89
|
-
|
|
90
|
-
// set a default listener the is used for forwarding/completing responses
|
|
91
|
-
functionMapping['messaging:response'] = _handleResponse;
|
|
92
|
-
processContext.on('messaging:response', _handleResponse);
|
|
93
|
-
|
|
94
|
-
function _handleResponse(msgResponse) {
|
|
95
|
-
// if msg has returned to source then emit it else pass it along
|
|
96
|
-
if (msgResponse.__source === config.assignment) {
|
|
97
|
-
logger.trace(`node message ${msgResponse.__msgId} has been processed`);
|
|
98
|
-
// we are in the right spot, emit to complete the promise from send
|
|
99
|
-
events.emit(msgResponse.__msgId, msgResponse);
|
|
100
|
-
} else {
|
|
101
|
-
_forwardMessage(msgResponse);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function respond(incoming, outgoing) {
|
|
106
|
-
const outgoingResponse = (outgoing && typeof outgoing === 'object') ? outgoing : {};
|
|
107
|
-
if (incoming.__msgId) {
|
|
108
|
-
outgoingResponse.__msgId = incoming.__msgId;
|
|
109
|
-
}
|
|
110
|
-
outgoingResponse.__source = incoming.__source;
|
|
111
|
-
outgoingResponse.message = 'messaging:response';
|
|
112
|
-
outgoingResponse.to = incoming.__source;
|
|
113
|
-
return send(outgoingResponse);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function _findAndSend(filterFn, msg, msgHookFn) {
|
|
117
|
-
const childProcesses = context.cluster.workers;
|
|
118
|
-
const children = _.filter(childProcesses, filterFn);
|
|
119
|
-
if (children.length === 0 && msg.response) {
|
|
120
|
-
// if there are no child processes found and it needs a response, answer back so
|
|
121
|
-
// that it does not hold for a long time
|
|
122
|
-
respond(msg);
|
|
123
|
-
}
|
|
124
|
-
children.forEach((childProcess) => {
|
|
125
|
-
if (msgHookFn) msgHookFn(childProcess);
|
|
126
|
-
if (childProcess.connected) {
|
|
127
|
-
childProcess.send(msg);
|
|
128
|
-
} else {
|
|
129
|
-
logger.warn('cannot send message to process', msg);
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function _sendToProcesses(msg) {
|
|
135
|
-
const msgExId = msg.ex_id || _.get(msg, 'payload.ex_id');
|
|
136
|
-
if (msgExId) {
|
|
137
|
-
// all processes that have the same assignment and exId
|
|
138
|
-
const filterFn = (process) => {
|
|
139
|
-
if (process.assignment !== msg.to) return false;
|
|
140
|
-
if (process.ex_id !== msgExId) return false;
|
|
141
|
-
return true;
|
|
142
|
-
};
|
|
143
|
-
_findAndSend(filterFn, msg);
|
|
144
|
-
} else {
|
|
145
|
-
// all processes that have the same assignment
|
|
146
|
-
const filterFn = (process) => process.assignment === msg.to;
|
|
147
|
-
_findAndSend(filterFn, msg);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function register(eventConfig) {
|
|
152
|
-
const eventName = eventConfig.event;
|
|
153
|
-
const { callback, identifier } = eventConfig;
|
|
154
|
-
|
|
155
|
-
const selfHasEvent = _.some(selfMessages, (type) => type[eventName] != null);
|
|
156
|
-
if (!selfHasEvent) {
|
|
157
|
-
throw new Error(`"${self}" cannot register for event, "${eventName}", in messaging module`);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (selfMessages.ipc[eventName]) {
|
|
161
|
-
const realKey = selfMessages.ipc[eventName];
|
|
162
|
-
// this needs to be directly allocated so that IPC messaging can happen if
|
|
163
|
-
// network was not instantiated
|
|
164
|
-
processContext.on(realKey, callback);
|
|
165
|
-
} else {
|
|
166
|
-
// we attach events etc later when the connection is made, this is async
|
|
167
|
-
// while others are sync registration
|
|
168
|
-
let trueEventName = selfMessages.network[eventName];
|
|
169
|
-
|
|
170
|
-
if (!trueEventName) trueEventName = selfMessages.intraProcess[eventName];
|
|
171
|
-
if (identifier) callback.__socketIdentifier = identifier;
|
|
172
|
-
functionMapping[trueEventName] = callback;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function _registerFns(socket) {
|
|
177
|
-
_.forOwn(functionMapping, (func, key) => {
|
|
178
|
-
if (func.__socketIdentifier) {
|
|
179
|
-
const wrappedFunc = (msg = {}) => {
|
|
180
|
-
const identifier = func.__socketIdentifier;
|
|
181
|
-
let id = msg[identifier];
|
|
182
|
-
// if already set, extract value else set it on socket
|
|
183
|
-
if (socket[identifier]) {
|
|
184
|
-
id = socket[identifier];
|
|
185
|
-
} else {
|
|
186
|
-
socket[identifier] = id;
|
|
187
|
-
}
|
|
188
|
-
// if network host (slicer, cluster_master) and connection
|
|
189
|
-
// or retry event, join room
|
|
190
|
-
if (key === 'node:online') {
|
|
191
|
-
const rooms = Object.keys(socket.rooms);
|
|
192
|
-
const hasRoom = _.some(rooms, (r) => r === id);
|
|
193
|
-
if (!hasRoom) {
|
|
194
|
-
logger.info(`joining room ${id}`);
|
|
195
|
-
socket.join(id);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
// not all events have messages, if so then pass it, else just pass identifier
|
|
199
|
-
if (msg) {
|
|
200
|
-
func(msg, id, identifier);
|
|
201
|
-
} else {
|
|
202
|
-
func(id);
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
socket.on(key, wrappedFunc);
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
logger.trace(`setting listener key ${key}`);
|
|
211
|
-
|
|
212
|
-
socket.on(key, func);
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function _determinePathForMessage(messageSent) {
|
|
217
|
-
const { to } = messageSent;
|
|
218
|
-
let destinationType = routing[self][to];
|
|
219
|
-
// cluster_master has two types of connections to node_master, if it does not have a
|
|
220
|
-
// address then its talking to its own node_master through ipc
|
|
221
|
-
// TODO: reference self message, remove cluster_master specific code
|
|
222
|
-
if (self === 'cluster_master' && !messageSent.address && clusterMasterMessages.ipc[messageSent.message]) {
|
|
223
|
-
destinationType = 'ipc';
|
|
224
|
-
}
|
|
225
|
-
if (destinationType === undefined) {
|
|
226
|
-
throw new Error(`could not determine how to pass on message to: ${JSON.stringify(messageSent)}`);
|
|
227
|
-
}
|
|
228
|
-
return destinationType;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// join rooms before on connect to avoid race conditions
|
|
232
|
-
function _attachRoomsSocketIO() {
|
|
233
|
-
if (!io) return;
|
|
234
|
-
|
|
235
|
-
// middleware
|
|
236
|
-
io.use((socket, next) => {
|
|
237
|
-
const {
|
|
238
|
-
node_id: nodeId,
|
|
239
|
-
} = socket.handshake.query;
|
|
240
|
-
|
|
241
|
-
if (nodeId) {
|
|
242
|
-
logger.info(`node ${nodeId} joining room on connect`);
|
|
243
|
-
socket.join(nodeId);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return next();
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
function listen({ server, query } = {}) {
|
|
251
|
-
messsagingOnline = true;
|
|
252
|
-
|
|
253
|
-
if (config.clients.networkClient) {
|
|
254
|
-
// node_master, worker
|
|
255
|
-
io = require('socket.io-client')(hostURL, {
|
|
256
|
-
forceNew: true,
|
|
257
|
-
path: '/native-clustering',
|
|
258
|
-
perMessageDeflate: false,
|
|
259
|
-
query,
|
|
260
|
-
});
|
|
261
|
-
_registerFns(io);
|
|
262
|
-
if (self === 'node_master') {
|
|
263
|
-
io.on('networkMessage', (networkMsg) => {
|
|
264
|
-
const { message } = networkMsg;
|
|
265
|
-
const func = functionMapping[message];
|
|
266
|
-
if (func) {
|
|
267
|
-
func(networkMsg);
|
|
268
|
-
} else {
|
|
269
|
-
// if no function is registered, it is meant to by passed along to child
|
|
270
|
-
_sendToProcesses(networkMsg);
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
logger.debug('client network connection is online');
|
|
275
|
-
} else if (server) {
|
|
276
|
-
// cluster_master
|
|
277
|
-
io = require('socket.io')(server, {
|
|
278
|
-
path: '/native-clustering',
|
|
279
|
-
pingTimeout: configTimeout,
|
|
280
|
-
pingInterval: configTimeout + networkLatencyBuffer,
|
|
281
|
-
perMessageDeflate: false,
|
|
282
|
-
serveClient: false,
|
|
283
|
-
});
|
|
284
|
-
_attachRoomsSocketIO();
|
|
285
|
-
|
|
286
|
-
io.on('connection', (socket) => {
|
|
287
|
-
logger.debug('a connection to cluster_master has been made');
|
|
288
|
-
_registerFns(socket);
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// TODO: message queuing will be used until formal process lifecycles are implemented
|
|
293
|
-
while (messagingQueue.size() > 0) {
|
|
294
|
-
const cachedMessages = messagingQueue.dequeue();
|
|
295
|
-
// they are put in as a tuple, [realMsg, ipcMessage]
|
|
296
|
-
processContext.emit(cachedMessages[0], cachedMessages[1]);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
function broadcast(eventName, payload = {}) {
|
|
301
|
-
logger.trace('broadcasting a network message', { eventName, payload });
|
|
302
|
-
if (!payload.message) payload.message = eventName;
|
|
303
|
-
io.emit('networkMessage', payload);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
function _forwardMessage(messageSent) {
|
|
307
|
-
const messageType = _determinePathForMessage(messageSent);
|
|
308
|
-
if (messageType === 'network') {
|
|
309
|
-
// worker and node_master communicate through broadcast to slicer/cluster_master
|
|
310
|
-
if (self === 'node_master') {
|
|
311
|
-
io.emit(messageSent.message, messageSent);
|
|
312
|
-
} else if (self === 'cluster_master') {
|
|
313
|
-
io.sockets.in(messageSent.address).emit('networkMessage', messageSent);
|
|
314
|
-
} else {
|
|
315
|
-
io.sockets.in(messageSent.address).emit(messageSent.message, messageSent);
|
|
316
|
-
}
|
|
317
|
-
} else if (self === 'node_master') {
|
|
318
|
-
_sendToProcesses(messageSent);
|
|
319
|
-
} else if (processContext) {
|
|
320
|
-
if (processContext.connected) {
|
|
321
|
-
processContext.send(messageSent);
|
|
322
|
-
} else {
|
|
323
|
-
logger.warn('cannot send to process because it is not connected', messageSent);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
function send(messageSent) {
|
|
329
|
-
if (!messageSent.__source) messageSent.__source = self;
|
|
330
|
-
const needsReply = messageSent.response;
|
|
331
|
-
|
|
332
|
-
if (!needsReply) {
|
|
333
|
-
_forwardMessage(messageSent);
|
|
334
|
-
return Promise.resolve(true);
|
|
335
|
-
}
|
|
336
|
-
return new Promise((resolve, reject) => {
|
|
337
|
-
let timer;
|
|
338
|
-
const msgID = nanoid(8);
|
|
339
|
-
const actionTimeout = messageSent.timeout || configTimeout;
|
|
340
|
-
const messageTimeout = _.toNumber(actionTimeout) + networkLatencyBuffer;
|
|
341
|
-
messageSent.__msgId = msgID;
|
|
342
|
-
|
|
343
|
-
events.once(msgID, (nodeMasterData) => {
|
|
344
|
-
clearTimeout(timer);
|
|
345
|
-
if (nodeMasterData.error) {
|
|
346
|
-
reject(new Error(`${nodeMasterData.error} occurred on node: ${nodeMasterData.__source}`));
|
|
347
|
-
} else {
|
|
348
|
-
resolve(nodeMasterData);
|
|
349
|
-
}
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
_forwardMessage(messageSent);
|
|
353
|
-
timer = setTimeout(() => {
|
|
354
|
-
// remove listener to prevent memory leaks
|
|
355
|
-
events.removeAllListeners(msgID);
|
|
356
|
-
reject(new Error(`timeout error while communicating with ${messageSent.to}, msg: ${messageSent.message}, data: ${JSON.stringify(messageSent)}`));
|
|
357
|
-
}, messageTimeout);
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
function _makeConfigurations() {
|
|
362
|
-
let host;
|
|
363
|
-
let port;
|
|
364
|
-
const options = {
|
|
365
|
-
node_master: { networkClient: true, ipcClient: false },
|
|
366
|
-
cluster_master: { networkClient: false, ipcClient: true },
|
|
367
|
-
execution_controller: { networkClient: false, ipcClient: true },
|
|
368
|
-
worker: { networkClient: true, ipcClient: true },
|
|
369
|
-
assets_service: { networkClient: true, ipcClient: true }
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
const env = context.__testingModule ? context.__testingModule.env : process.env;
|
|
373
|
-
const processConfig = {};
|
|
374
|
-
processConfig.clients = options[env.assignment];
|
|
375
|
-
|
|
376
|
-
if (processConfig.clients.ipcClient) {
|
|
377
|
-
// all children of node_master
|
|
378
|
-
processContext = context.__testingModule ? context.__testingModule : process;
|
|
379
|
-
} else {
|
|
380
|
-
// node_master
|
|
381
|
-
processContext = context.cluster;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
if (processConfig.clients.networkClient) {
|
|
385
|
-
if (env.assignment === 'node_master' || env.assignment === 'assets_service') {
|
|
386
|
-
host = context.sysconfig.teraslice.master_hostname;
|
|
387
|
-
({ port } = context.sysconfig.teraslice);
|
|
388
|
-
}
|
|
389
|
-
processConfig.hostURL = _makeHostName(host, port);
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
processConfig.assignment = env.assignment;
|
|
393
|
-
|
|
394
|
-
return processConfig;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
function _makeHostName(host, port, nameSpace) {
|
|
398
|
-
let name;
|
|
399
|
-
let hostname = host;
|
|
400
|
-
|
|
401
|
-
if (!hostname.match(/http/)) {
|
|
402
|
-
hostname = `http://${hostname}`;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
const lastChar = hostname[hostname.length - 1];
|
|
406
|
-
|
|
407
|
-
if (lastChar !== ':') {
|
|
408
|
-
name = `${hostname}:${port}`;
|
|
409
|
-
} else {
|
|
410
|
-
name = hostname + port;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
if (nameSpace) {
|
|
414
|
-
return `${name}/${nameSpace}`;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
return name;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
function _getMessages(type) {
|
|
421
|
-
if (type === 'cluster_master') return clusterMasterMessages;
|
|
422
|
-
if (type === 'node_master') return nodeMasterMessages;
|
|
423
|
-
if (type === 'assets_service') return assetServiceMessages;
|
|
424
|
-
return new Error(`could not find message model for type: ${type}`);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
function getHostUrl() {
|
|
428
|
-
if (hostURL) {
|
|
429
|
-
return hostURL;
|
|
430
|
-
}
|
|
431
|
-
return null;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
function getClientCounts() {
|
|
435
|
-
if (io) {
|
|
436
|
-
return io.eio.clientsCount;
|
|
437
|
-
}
|
|
438
|
-
// there are no connected clients because the network is not instantiated
|
|
439
|
-
return 0;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
function listRooms() {
|
|
443
|
-
const connected = _.get(io, 'sockets.connected', {});
|
|
444
|
-
|
|
445
|
-
if (_.isEmpty(connected)) return [];
|
|
446
|
-
|
|
447
|
-
const allRooms = _.map(connected, ({ rooms }) => _.keys(rooms));
|
|
448
|
-
|
|
449
|
-
return _.flatten(allRooms);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
function registerChildOnlineHook(fn) {
|
|
453
|
-
childHookFn = fn;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
function isExecutionStateQuery(msg) {
|
|
457
|
-
const stateQuery = {
|
|
458
|
-
'cluster:execution:pause': 'cluster:execution:pause',
|
|
459
|
-
'cluster:execution:resume': 'cluster:execution:resume',
|
|
460
|
-
'cluster:slicer:analytics': 'cluster:slicer:analytics',
|
|
461
|
-
};
|
|
462
|
-
|
|
463
|
-
return stateQuery[msg] !== undefined;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
function emitIpcMessage(fn) {
|
|
467
|
-
return (ipcMessage) => {
|
|
468
|
-
const msg = ipcMessage.message;
|
|
469
|
-
const realMsg = _.get(selfMessages, `ipc.${msg}`, null);
|
|
470
|
-
if (realMsg) {
|
|
471
|
-
fn(realMsg, ipcMessage);
|
|
472
|
-
} else {
|
|
473
|
-
logger.error(`process: ${self} has received a message: ${msg}, which is not registered in the messaging module`);
|
|
474
|
-
}
|
|
475
|
-
};
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
function handleIpcMessages() {
|
|
479
|
-
if (self === 'execution_controller') {
|
|
480
|
-
const checkAndEmit = (realMsg, ipcMessage) => {
|
|
481
|
-
if (messsagingOnline || !isExecutionStateQuery(realMsg)) {
|
|
482
|
-
processContext.emit(realMsg, ipcMessage);
|
|
483
|
-
} else {
|
|
484
|
-
messagingQueue.enqueue([realMsg, ipcMessage]);
|
|
485
|
-
}
|
|
486
|
-
};
|
|
487
|
-
return emitIpcMessage(checkAndEmit);
|
|
488
|
-
}
|
|
489
|
-
// for everything else just emit the message
|
|
490
|
-
const emitFn = (realMsg, ipcMessage) => processContext.emit(realMsg, ipcMessage);
|
|
491
|
-
return emitIpcMessage(emitFn);
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
// all child processes need to set up a process listener on the 'message' event
|
|
495
|
-
if (config.clients.ipcClient) {
|
|
496
|
-
process.on('message', handleIpcMessages());
|
|
497
|
-
} else {
|
|
498
|
-
processContext.on('online', (worker) => {
|
|
499
|
-
logger.debug('worker process has come online');
|
|
500
|
-
if (childHookFn) {
|
|
501
|
-
childHookFn();
|
|
502
|
-
}
|
|
503
|
-
const contextWorker = processContext.workers[worker.id];
|
|
504
|
-
|
|
505
|
-
// don't double subscribe
|
|
506
|
-
contextWorker.removeListener('message', _handleWorkerMessage);
|
|
507
|
-
|
|
508
|
-
// set up a message handler on each child created, if a child is talking to cluster
|
|
509
|
-
// then pass it on, else invoke process event handler on node_master
|
|
510
|
-
contextWorker.on('message', _handleWorkerMessage);
|
|
511
|
-
});
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
function _handleWorkerMessage(ipcMessage) {
|
|
515
|
-
if (ipcMessage.to === 'cluster_master') {
|
|
516
|
-
logger.trace('network passing process message', ipcMessage.message, ipcMessage);
|
|
517
|
-
send(ipcMessage);
|
|
518
|
-
} else if (ipcMessage.to === 'node_master') {
|
|
519
|
-
logger.trace('process message', ipcMessage.message, ipcMessage);
|
|
520
|
-
processContext.emit(ipcMessage.message, ipcMessage);
|
|
521
|
-
} else {
|
|
522
|
-
_sendToProcesses(ipcMessage);
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
function testContext(_io) {
|
|
527
|
-
if (_io) io = _io;
|
|
528
|
-
|
|
529
|
-
return {
|
|
530
|
-
_sendToProcesses,
|
|
531
|
-
_registerFns,
|
|
532
|
-
_determinePathForMessage,
|
|
533
|
-
_forwardMessage,
|
|
534
|
-
_makeConfigurations,
|
|
535
|
-
_makeHostName,
|
|
536
|
-
_getMessages,
|
|
537
|
-
_handleResponse,
|
|
538
|
-
_getRegistry: () => functionMapping,
|
|
539
|
-
routing
|
|
540
|
-
};
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
async function shutdown() {
|
|
544
|
-
if (io && _.isFunction(io.close)) {
|
|
545
|
-
io.close();
|
|
546
|
-
await pDelay(100);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
return {
|
|
551
|
-
register,
|
|
552
|
-
listen,
|
|
553
|
-
getHostUrl,
|
|
554
|
-
getClientCounts,
|
|
555
|
-
listRooms,
|
|
556
|
-
send,
|
|
557
|
-
respond,
|
|
558
|
-
broadcast,
|
|
559
|
-
registerChildOnlineHook,
|
|
560
|
-
shutdown,
|
|
561
|
-
__test_context: testContext
|
|
562
|
-
};
|
|
563
|
-
};
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const _ = require('lodash');
|
|
4
|
-
|
|
5
|
-
function _iterateState(clusterState, cb) {
|
|
6
|
-
// I clone here, because the code below accidentally modifies clusterState.
|
|
7
|
-
// Not sure if this is the best chouice.
|
|
8
|
-
return _.chain(_.cloneDeep(clusterState))
|
|
9
|
-
.filter((node) => node.state === 'connected')
|
|
10
|
-
.map((node) => {
|
|
11
|
-
const workers = node.active.filter(cb);
|
|
12
|
-
|
|
13
|
-
return workers.map((worker) => {
|
|
14
|
-
worker.node_id = node.node_id;
|
|
15
|
-
worker.hostname = node.hostname;
|
|
16
|
-
return worker;
|
|
17
|
-
});
|
|
18
|
-
})
|
|
19
|
-
.flatten()
|
|
20
|
-
.value();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function findAllSlicers(clusterState) {
|
|
24
|
-
return _iterateState(
|
|
25
|
-
clusterState,
|
|
26
|
-
(worker) => worker.assignment === 'execution_controller'
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function findWorkersByExecutionID(clusterState, exId) {
|
|
31
|
-
return _iterateState(
|
|
32
|
-
clusterState,
|
|
33
|
-
(worker) => worker.assignment === 'worker' && worker.ex_id === exId
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function findSlicersByExecutionID(clusterState, exIdDict) {
|
|
38
|
-
return _iterateState(
|
|
39
|
-
clusterState,
|
|
40
|
-
(worker) => worker.assignment === 'execution_controller' && exIdDict[worker.ex_id]
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
module.exports = {
|
|
45
|
-
_iterateState, // Exporting so it can be tested
|
|
46
|
-
findAllSlicers,
|
|
47
|
-
findWorkersByExecutionID,
|
|
48
|
-
findSlicersByExecutionID,
|
|
49
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
module.exports = function clustering(context, { clusterMasterServer }) {
|
|
4
|
-
const clusterType = context.sysconfig.teraslice.cluster_manager_type;
|
|
5
|
-
|
|
6
|
-
if (clusterType === 'native') {
|
|
7
|
-
return require('./backends/native')(context, clusterMasterServer);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
if (clusterType === 'kubernetes') {
|
|
11
|
-
return require('./backends/kubernetes')(context, clusterMasterServer);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
throw new Error(`unknown cluster service ${clusterType}, cannot find cluster module`);
|
|
15
|
-
};
|