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.
Files changed (69) hide show
  1. package/cluster-service.js +24 -18
  2. package/dist/src/index.js +42 -0
  3. package/package.json +11 -15
  4. package/service.js +4 -6
  5. package/worker-service.js +6 -6
  6. package/index.js +0 -21
  7. package/lib/cluster/cluster_master.js +0 -164
  8. package/lib/cluster/node_master.js +0 -393
  9. package/lib/cluster/services/api.js +0 -581
  10. package/lib/cluster/services/assets.js +0 -211
  11. package/lib/cluster/services/cluster/backends/kubernetes/deployments/worker.hbs +0 -86
  12. package/lib/cluster/services/cluster/backends/kubernetes/index.js +0 -225
  13. package/lib/cluster/services/cluster/backends/kubernetes/jobs/execution_controller.hbs +0 -69
  14. package/lib/cluster/services/cluster/backends/kubernetes/k8s.js +0 -450
  15. package/lib/cluster/services/cluster/backends/kubernetes/k8sResource.js +0 -443
  16. package/lib/cluster/services/cluster/backends/kubernetes/k8sState.js +0 -67
  17. package/lib/cluster/services/cluster/backends/kubernetes/utils.js +0 -58
  18. package/lib/cluster/services/cluster/backends/native/index.js +0 -611
  19. package/lib/cluster/services/cluster/backends/native/messaging.js +0 -563
  20. package/lib/cluster/services/cluster/backends/state-utils.js +0 -49
  21. package/lib/cluster/services/cluster/index.js +0 -15
  22. package/lib/cluster/services/execution.js +0 -459
  23. package/lib/cluster/services/jobs.js +0 -303
  24. package/lib/config/default-sysconfig.js +0 -47
  25. package/lib/config/index.js +0 -32
  26. package/lib/config/schemas/system.js +0 -333
  27. package/lib/processors/save_file/index.js +0 -9
  28. package/lib/processors/save_file/processor.js +0 -17
  29. package/lib/processors/save_file/schema.js +0 -17
  30. package/lib/processors/script.js +0 -130
  31. package/lib/processors/stdout/index.js +0 -9
  32. package/lib/processors/stdout/processor.js +0 -19
  33. package/lib/processors/stdout/schema.js +0 -18
  34. package/lib/storage/analytics.js +0 -106
  35. package/lib/storage/assets.js +0 -275
  36. package/lib/storage/backends/elasticsearch_store.js +0 -567
  37. package/lib/storage/backends/mappings/analytics.json +0 -49
  38. package/lib/storage/backends/mappings/asset.json +0 -40
  39. package/lib/storage/backends/mappings/ex.json +0 -55
  40. package/lib/storage/backends/mappings/job.json +0 -31
  41. package/lib/storage/backends/mappings/state.json +0 -37
  42. package/lib/storage/execution.js +0 -331
  43. package/lib/storage/index.js +0 -16
  44. package/lib/storage/jobs.js +0 -97
  45. package/lib/storage/state.js +0 -302
  46. package/lib/utils/api_utils.js +0 -173
  47. package/lib/utils/asset_utils.js +0 -117
  48. package/lib/utils/date_utils.js +0 -58
  49. package/lib/utils/encoding_utils.js +0 -29
  50. package/lib/utils/events.js +0 -7
  51. package/lib/utils/file_utils.js +0 -118
  52. package/lib/utils/id_utils.js +0 -19
  53. package/lib/utils/port_utils.js +0 -83
  54. package/lib/workers/assets/loader.js +0 -109
  55. package/lib/workers/assets/spawn.js +0 -78
  56. package/lib/workers/context/execution-context.js +0 -16
  57. package/lib/workers/context/terafoundation-context.js +0 -10
  58. package/lib/workers/execution-controller/execution-analytics.js +0 -211
  59. package/lib/workers/execution-controller/index.js +0 -1033
  60. package/lib/workers/execution-controller/recovery.js +0 -188
  61. package/lib/workers/execution-controller/scheduler.js +0 -461
  62. package/lib/workers/execution-controller/slice-analytics.js +0 -115
  63. package/lib/workers/helpers/job.js +0 -93
  64. package/lib/workers/helpers/op-analytics.js +0 -22
  65. package/lib/workers/helpers/terafoundation.js +0 -43
  66. package/lib/workers/helpers/worker-shutdown.js +0 -187
  67. package/lib/workers/metrics/index.js +0 -139
  68. package/lib/workers/worker/index.js +0 -344
  69. package/lib/workers/worker/slice.js +0 -143
@@ -1,188 +0,0 @@
1
- 'use strict';
2
-
3
- const {
4
- pRaceWithTimeout, logError, cloneDeep, Queue
5
- } = require('@terascope/utils');
6
- const { makeLogger } = require('../helpers/terafoundation');
7
-
8
- function recoveryModule(context, stateStore, executionContext) {
9
- const events = context.apis.foundation.getSystemEvents();
10
- const slicersToRecover = executionContext.config.slicers;
11
- const recoveryQueue = new Queue();
12
-
13
- const cleanupType = executionContext.config.recovered_slice_type;
14
- const recoverExecution = executionContext.config.recovered_execution;
15
- const autorecover = Boolean(executionContext.config.autorecover);
16
- const { exId } = executionContext;
17
-
18
- let recoverComplete = true;
19
- let isShutdown = false;
20
-
21
- const logger = makeLogger(context, 'execution_recovery');
22
-
23
- const retryState = {};
24
-
25
- function initialize() {
26
- events.on('slice:success', _sliceComplete);
27
- recoverComplete = false;
28
-
29
- // once we have fully recovered, clean up event listners
30
- events.once('execution:recovery:complete', () => {
31
- events.removeListener('slice:success', _sliceComplete);
32
- });
33
- }
34
-
35
- function _sliceComplete(sliceData) {
36
- retryState[sliceData.slice.slice_id] = false;
37
- }
38
-
39
- function _setId(slice) {
40
- retryState[slice.slice_id] = true;
41
- }
42
-
43
- async function _processIncompleteSlices(slicerID) {
44
- const slices = await stateStore.recoverSlices(recoverExecution, slicerID, cleanupType);
45
- slices.forEach((slice) => {
46
- _setId(slice);
47
- recoveryQueue.enqueue(slice);
48
- });
49
-
50
- return slices.length;
51
- }
52
-
53
- function _recoveryBatchCompleted() {
54
- return Object.values(retryState).every((v) => v === false);
55
- }
56
-
57
- function _retryState() {
58
- return cloneDeep(retryState);
59
- }
60
-
61
- function _waitForRecoveryBatchCompletion() {
62
- return new Promise((resolve) => {
63
- const checkingBatch = setInterval(() => {
64
- if (_recoveryBatchCompleted()) {
65
- clearInterval(checkingBatch);
66
- events.emit('execution:recovery:complete');
67
- recoverComplete = true;
68
- resolve();
69
- return;
70
- }
71
-
72
- if (isShutdown) {
73
- clearInterval(checkingBatch);
74
- recoverComplete = false;
75
- resolve();
76
- }
77
- }, 100);
78
- });
79
- }
80
-
81
- let slicerID = 0;
82
-
83
- async function handle() {
84
- if (recoverComplete) return true;
85
-
86
- const recoveredSlicesCount = await _processIncompleteSlices(slicerID);
87
- if (recoveredSlicesCount === 0) {
88
- slicerID++;
89
- // all slicers have been recovered
90
- if (slicerID > slicersToRecover) {
91
- logger.warn(`recovered data for execution: ${exId} has successfully been enqueued`);
92
- await _waitForRecoveryBatchCompletion();
93
- return true;
94
- }
95
- }
96
-
97
- await _waitForRecoveryBatchCompletion();
98
-
99
- return false;
100
- }
101
-
102
- function getSlice() {
103
- if (recoveryQueue.size() > 0) {
104
- return recoveryQueue.dequeue();
105
- }
106
- return null;
107
- }
108
-
109
- function getSlices(max = 1) {
110
- const count = max > sliceCount() ? sliceCount() : max;
111
-
112
- const slices = [];
113
-
114
- for (let i = 0; i < count; i++) {
115
- const slice = recoveryQueue.dequeue();
116
- if (!slice) return slices;
117
-
118
- slices.push(slice);
119
- }
120
-
121
- return slices;
122
- }
123
-
124
- function sliceCount() {
125
- return recoveryQueue.size();
126
- }
127
-
128
- async function shutdown() {
129
- let checkInterval;
130
-
131
- try {
132
- await pRaceWithTimeout(
133
- new Promise((resolve) => {
134
- checkInterval = setInterval(() => {
135
- if (recoverComplete) {
136
- resolve();
137
- }
138
- }, 100);
139
- }),
140
- context.sysconfig.teraslice.shutdown_timeout,
141
- (err) => { logError(logger, err); }
142
- );
143
- } finally {
144
- isShutdown = true;
145
- clearInterval(checkInterval);
146
- }
147
- }
148
-
149
- function recoveryComplete() {
150
- return recoverComplete;
151
- }
152
-
153
- /**
154
- * Whether or not the execution will continue to process
155
- * slices after recovering.
156
- *
157
- * @returns {boolean}
158
- */
159
- function exitAfterComplete() {
160
- if (autorecover) return false;
161
- if (!cleanupType) return false;
162
- return true;
163
- }
164
-
165
- function testContext() {
166
- return {
167
- _retryState,
168
- _recoveryBatchCompleted,
169
- _setId,
170
- _waitForRecoveryBatchCompletion,
171
- _sliceComplete
172
- };
173
- }
174
-
175
- return {
176
- initialize,
177
- getSlice,
178
- getSlices,
179
- sliceCount,
180
- exitAfterComplete,
181
- recoveryComplete,
182
- handle,
183
- shutdown,
184
- __test_context: testContext
185
- };
186
- }
187
-
188
- module.exports = recoveryModule;
@@ -1,461 +0,0 @@
1
- 'use strict';
2
-
3
- const {
4
- Queue, noop, pDelay, get, toString, makeISODate, logError, pWhile
5
- } = require('@terascope/utils');
6
- const makeExecutionRecovery = require('./recovery');
7
- const { makeLogger } = require('../helpers/terafoundation');
8
-
9
- class Scheduler {
10
- constructor(context, executionContext) {
11
- this.context = context;
12
- this.logger = makeLogger(context, 'execution_scheduler');
13
- this.events = context.apis.foundation.getSystemEvents();
14
- this.executionContext = executionContext;
15
- this.exId = executionContext.exId;
16
-
17
- const recoverFromExId = get(executionContext.config, 'recovered_execution');
18
- const slicerCanRecover = executionContext.slicer().isRecoverable();
19
- if (recoverFromExId && !slicerCanRecover) {
20
- throw new Error('Slicer is not recoverable');
21
- }
22
-
23
- this.recoverFromExId = recoverFromExId;
24
- this.recoverExecution = Boolean(recoverFromExId && slicerCanRecover);
25
- this.recovering = Boolean(this.recoverExecution);
26
- this.autorecover = Boolean(executionContext.config.autorecover);
27
-
28
- this._creating = 0;
29
- this.ready = false;
30
- this.paused = true;
31
- this.stopped = false;
32
- this.slicersDone = false;
33
- this.slicersFailed = false;
34
- this.queue = new Queue();
35
- this.startingPoints = [];
36
-
37
- this._resolveRun = noop;
38
- this._processCleanup = noop;
39
-
40
- this._processSlicers();
41
- }
42
-
43
- /**
44
- * Initialize the recovery instance or the execution context,
45
- * if recovery is initialized, the execution context will not be
46
- * initialized until the execution if finished and the cleanup
47
- * type is set.
48
- */
49
- async initialize() {
50
- if (this.recoverExecution) {
51
- await this._initializeRecovery();
52
- return;
53
- }
54
-
55
- await this._initializeExecution();
56
- }
57
-
58
- /**
59
- * Run the execution, this will block until complete (or failed)
60
- */
61
- async run() {
62
- if (this.recoverExecution) {
63
- await this.exStore.setStatus(this.exId, 'recovering');
64
-
65
- this.logger.info(`execution: ${this.exId} is starting in recovery mode`);
66
- this.ready = true;
67
- this.start();
68
-
69
- await this._waitForRecovery();
70
- await this._recoveryComplete();
71
-
72
- if (this.recover.exitAfterComplete()) {
73
- return;
74
- }
75
-
76
- await this._initializeExecution();
77
- }
78
-
79
- await this.exStore.setStatus(this.exId, 'running');
80
- this.ready = true;
81
-
82
- const promise = new Promise((resolve) => {
83
- const handler = (err) => {
84
- if (err) {
85
- this.slicersFailed = true;
86
- } else {
87
- this.slicersDone = true;
88
- }
89
- this._resolveRun();
90
- this._resolveRun = noop;
91
- };
92
-
93
- this._resolveRun = () => {
94
- this.events.removeListener('slicers:finished', handler);
95
- resolve();
96
- };
97
-
98
- this.events.once('slicers:finished', handler);
99
- });
100
-
101
- this.start();
102
-
103
- this.logger.trace('running the scheduler');
104
-
105
- await promise;
106
-
107
- const n = this.pendingSlices + this.pendingSlicerCount;
108
- this.logger.debug(
109
- `execution ${this.exId} is finished scheduling, ${n} remaining slices in the queue`
110
- );
111
-
112
- await pWhile(async () => {
113
- if (!this._creating) return true;
114
- await pDelay(100);
115
- return false;
116
- });
117
- }
118
-
119
- start() {
120
- this.paused = false;
121
- }
122
-
123
- async stop() {
124
- if (this.stopped) return;
125
-
126
- this.logger.debug('stopping scheduler...');
127
-
128
- this.stopped = true;
129
-
130
- const drain = this._drainPendingSlices(false);
131
-
132
- this._processCleanup();
133
- this._processCleanup = noop;
134
- this._resolveRun();
135
- this._resolveRun = noop;
136
-
137
- await drain;
138
- }
139
-
140
- pause() {
141
- this.paused = true;
142
- }
143
-
144
- get maxQueueLength() {
145
- return this.executionContext.slicer().maxQueueLength();
146
- }
147
-
148
- get queueLength() {
149
- return this.queue.size();
150
- }
151
-
152
- get isQueueFull() {
153
- const maxLength = this.maxQueueLength;
154
- return this.pendingSlices + this.pendingSlicerCount > maxLength;
155
- }
156
-
157
- get pendingSlicerCount() {
158
- if (!this.ready) return 0;
159
-
160
- if (this.recovering && this.recover) {
161
- return this.recover.sliceCount();
162
- }
163
-
164
- return this.executionContext.slicer().sliceCount();
165
- }
166
-
167
- get pendingSlices() {
168
- return this.queueLength + this._creating;
169
- }
170
-
171
- get queueRemainder() {
172
- const remainder = this.maxQueueLength - this.pendingSlices;
173
- return remainder > 0 ? remainder : 0;
174
- }
175
-
176
- get isFinished() {
177
- const isDone = this.slicersDone || this.slicersFailed || this.stopped;
178
- return isDone && !this.pendingSlices;
179
- }
180
-
181
- canAllocateSlice() {
182
- return this.ready && !this.paused && !this.isQueueFull;
183
- }
184
-
185
- canComplete() {
186
- const { lifecycle } = this.executionContext.config;
187
- return this.ready && lifecycle === 'once' && !this.recovering;
188
- }
189
-
190
- isRecovering() {
191
- return this.ready && this.recovering;
192
- }
193
-
194
- async shutdown() {
195
- await this.stop();
196
-
197
- if (this.recover) {
198
- try {
199
- await this.recover.shutdown();
200
- } catch (err) {
201
- logError(this.logger, err, 'failed to shutdown recovery');
202
- }
203
- }
204
-
205
- this.queue.each((slice) => {
206
- this.queue.remove(slice.slice_id, 'slice_id');
207
- });
208
- }
209
-
210
- getSlices(limit = 1) {
211
- if (this.queue.size() === 0) return [];
212
- if (limit < 1) return [];
213
-
214
- const slices = [];
215
-
216
- for (let i = 0; i < limit; i += 1) {
217
- const slice = this.queue.dequeue();
218
- if (slice == null) break;
219
-
220
- slices.push(slice);
221
- }
222
-
223
- if (slices.length > 0) {
224
- this.events.emit('slicers:queued', this.queueLength);
225
- }
226
-
227
- return slices;
228
- }
229
-
230
- enqueueSlice(slice, addToStart) {
231
- return this.enqueueSlices([slice], addToStart);
232
- }
233
-
234
- enqueueSlices(slices, addToStart = false) {
235
- if (this.stopped) return;
236
-
237
- slices.forEach((slice) => {
238
- if (this.queue.exists('slice_id', slice.slice_id)) {
239
- this.logger.warn(`slice ${slice.slice_id} has already been enqueued`);
240
- return;
241
- }
242
-
243
- this.logger.trace('enqueuing slice', slice);
244
-
245
- if (addToStart) {
246
- this.queue.unshift(slice);
247
- } else {
248
- this.queue.enqueue(slice);
249
- this.executionContext.onSliceEnqueued(slice);
250
- }
251
- });
252
-
253
- this.events.emit('slicers:queued', this.queueLength);
254
- }
255
-
256
- _processSlicers() {
257
- const { events, logger, exId } = this;
258
-
259
- let _handling = false;
260
- let _finished = false;
261
-
262
- let createInterval;
263
- let handleInterval;
264
-
265
- const resetCleanup = () => {
266
- this._processCleanup = noop;
267
- };
268
-
269
- const cleanup = () => {
270
- clearInterval(createInterval);
271
- createInterval = null;
272
- clearInterval(handleInterval);
273
- handleInterval = null;
274
- resetCleanup();
275
- };
276
-
277
- const drain = () => {
278
- const n = this.pendingSlicerCount;
279
- if (n) {
280
- logger.debug(`draining the remaining ${n} pending slices from the slicer`);
281
- }
282
- return this._drainPendingSlices(false);
283
- };
284
-
285
- const onSlicerFinished = async () => {
286
- cleanup();
287
- logger.info(`all slicers for execution: ${exId} have been completed`);
288
-
289
- await drain();
290
- events.emit('slicers:finished');
291
- };
292
-
293
- const onSlicerFailure = async (err) => {
294
- cleanup();
295
- logger.warn('slicer failed', toString(err));
296
-
297
- await drain();
298
-
299
- // before removing listeners make sure we've received all of the events
300
- await pDelay(100);
301
- events.emit('slicers:finished', err);
302
- };
303
-
304
- const makeSlices = async () => {
305
- try {
306
- if (this.recovering && this.recover) {
307
- _finished = await this.recover.handle();
308
- } else {
309
- _finished = await this.executionContext.slicer().handle();
310
- }
311
- } catch (err) {
312
- await onSlicerFailure(err);
313
- return;
314
- }
315
-
316
- if (!_finished) {
317
- return;
318
- }
319
-
320
- if (!this.recovering) {
321
- clearInterval(handleInterval);
322
- handleInterval = null;
323
- }
324
-
325
- if (this.canComplete()) {
326
- await onSlicerFinished();
327
- }
328
- };
329
-
330
- handleInterval = setInterval(() => {
331
- if (!this.canAllocateSlice()) return;
332
- if (_handling) return;
333
-
334
- _handling = true;
335
-
336
- makeSlices()
337
- .then(() => {
338
- _handling = false;
339
- })
340
- .catch((err) => {
341
- _handling = false;
342
- logError(this.logger, err, 'failure to run slicers');
343
- });
344
- }, 3);
345
-
346
- createInterval = setInterval(() => {
347
- if (!this.pendingSlicerCount) return;
348
-
349
- this._drainPendingSlices().catch(onSlicerFailure);
350
- }, 5);
351
-
352
- this._processCleanup = cleanup;
353
- }
354
-
355
- async _drainPendingSlices(once = true) {
356
- const slices = this._getPendingSlices();
357
- if (!slices.length) return;
358
-
359
- await this._createSlices(slices);
360
-
361
- if (once) return;
362
-
363
- await this._drainPendingSlices();
364
- }
365
-
366
- _getPendingSlices() {
367
- if (!this.ready) return [];
368
-
369
- if (this.recovering && this.recover) {
370
- return this.recover.getSlices(this.queueRemainder);
371
- }
372
-
373
- return this.executionContext.slicer().getSlices(this.queueRemainder);
374
- }
375
-
376
- async _createSlices(allSlices) {
377
- // filter out anything that doesn't need to be created
378
- const slices = [];
379
-
380
- for (const slice of allSlices) {
381
- // In the case of recovery slices have already been
382
- // created, so its important to skip this step
383
- if (slice._created) {
384
- this.enqueueSlice(slice);
385
- } else {
386
- slice._created = makeISODate();
387
- slices.push(slice);
388
- }
389
- }
390
-
391
- if (!slices.length) return;
392
-
393
- this._creating += slices.length;
394
-
395
- try {
396
- const count = await this.stateStore.createSlices(this.exId, slices);
397
- this.enqueueSlices(slices);
398
- this._creating -= count;
399
- } catch (err) {
400
- const { lifecycle } = this.executionContext.config;
401
- if (lifecycle === 'once') {
402
- throw err;
403
- } else {
404
- logError(this.logger, err, 'failure creating slices');
405
- }
406
- }
407
- }
408
-
409
- async _initializeRecovery() {
410
- this.recover = this.recover
411
- || makeExecutionRecovery(this.context, this.stateStore, this.executionContext);
412
-
413
- await this.recover.initialize();
414
-
415
- const { slicers: prevSlicers } = await this.exStore.get(this.recoverFromExId);
416
- this.events.emit('slicers:registered', prevSlicers);
417
- }
418
-
419
- async _initializeExecution() {
420
- await this.executionContext.initialize(this.startingPoints);
421
- const slicers = this.executionContext.slicer().slicers();
422
- this.events.emit('slicers:registered', slicers);
423
- }
424
-
425
- async _waitForRecovery() {
426
- if (!this.recoverExecution) return;
427
-
428
- if (!this.recover.recoveryComplete()) {
429
- await new Promise((resolve) => {
430
- this.events.once('execution:recovery:complete', () => {
431
- resolve();
432
- });
433
- });
434
- }
435
- }
436
-
437
- async _recoveryComplete() {
438
- this.recovering = false;
439
- this.ready = false;
440
-
441
- if (this.recover.exitAfterComplete()) {
442
- this.logger.warn('execution recovery has been marked as completed');
443
- this.slicersDone = true;
444
- this._processCleanup();
445
- this._processCleanup = noop;
446
- this._resolveRun();
447
- this._resolveRun = noop;
448
- return;
449
- }
450
-
451
- const { slicers: prevSlicers } = await this.exStore.get(this.recoverFromExId);
452
- this.startingPoints = await this.stateStore.getStartingPoints(
453
- this.recoverFromExId,
454
- prevSlicers,
455
- );
456
-
457
- this.logger.info(`execution: ${this.exId} finished its recovery`);
458
- }
459
- }
460
-
461
- module.exports = Scheduler;