teraslice 0.78.0 → 0.79.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.
@@ -8,10 +8,10 @@ const Request = require('kubernetes-client/backends/request');
8
8
  const { getRetryConfig } = require('./utils');
9
9
 
10
10
  class K8s {
11
- constructor(logger, clientConfig, defaultNamespace = 'default',
11
+ constructor(logger, clientConfig, defaultNamespace,
12
12
  apiPollDelay, shutdownTimeout) {
13
13
  this.apiPollDelay = apiPollDelay;
14
- this.defaultNamespace = defaultNamespace;
14
+ this.defaultNamespace = defaultNamespace || 'default';
15
15
  this.logger = logger;
16
16
  this.shutdownTimeout = shutdownTimeout; // this is in milliseconds
17
17
 
@@ -25,6 +25,7 @@ class K8sResource {
25
25
  constructor(resourceType, resourceName, terasliceConfig, execution) {
26
26
  this.execution = execution;
27
27
  this.jobLabelPrefix = 'job.teraslice.terascope.io';
28
+ this.jobPropertyLabelPrefix = 'job-property.teraslice.terascope.io';
28
29
  this.nodeType = resourceName;
29
30
  this.terasliceConfig = terasliceConfig;
30
31
 
@@ -54,6 +55,7 @@ class K8sResource {
54
55
  this._setImagePullSecret();
55
56
  this._setEphemeralStorage();
56
57
  this._setExternalPorts();
58
+ this._setPriorityClassName();
57
59
 
58
60
  if (resourceName === 'worker') {
59
61
  this._setWorkerAntiAffinity();
@@ -219,6 +221,25 @@ class K8sResource {
219
221
  }
220
222
  }
221
223
 
224
+ _setPriorityClassName() {
225
+ if (this.terasliceConfig.kubernetes_priority_class_name) {
226
+ if (this.nodeType === 'execution_controller') {
227
+ // eslint-disable-next-line max-len
228
+ this.resource.spec.template.spec.priorityClassName = this.terasliceConfig.kubernetes_priority_class_name;
229
+ if (this.execution.stateful) {
230
+ // eslint-disable-next-line max-len
231
+ this.resource.spec.template.metadata.labels[`${this.jobPropertyLabelPrefix}/stateful`] = 'true';
232
+ }
233
+ }
234
+ if (this.nodeType === 'worker' && this.execution.stateful) {
235
+ // eslint-disable-next-line max-len
236
+ this.resource.spec.template.spec.priorityClassName = this.terasliceConfig.kubernetes_priority_class_name;
237
+ // eslint-disable-next-line max-len
238
+ this.resource.spec.template.metadata.labels[`${this.jobPropertyLabelPrefix}/stateful`] = 'true';
239
+ }
240
+ }
241
+ }
242
+
222
243
  _setAssetsVolume() {
223
244
  if (this.terasliceConfig.assets_directory && this.terasliceConfig.assets_volume) {
224
245
  this.resource.spec.template.spec.volumes.push({
@@ -266,14 +287,40 @@ class K8sResource {
266
287
  _setResources() {
267
288
  let cpu;
268
289
  let memory;
290
+ let maxMemory;
291
+
292
+ const container = this.resource.spec.template.spec.containers[0];
269
293
 
270
294
  // use teraslice config as defaults and execution config will override it
271
295
  const envVars = Object.assign({}, this.terasliceConfig.env_vars, this.execution.env_vars);
272
296
 
273
297
  if (this.nodeType === 'worker') {
274
- // The settings on the executions override the cluster configs
275
- cpu = this.execution.cpu || this.terasliceConfig.cpu || -1;
276
- memory = this.execution.memory || this.terasliceConfig.memory || -1;
298
+ if (this.execution.resources_requests_cpu
299
+ || this.execution.resources_limits_cpu) {
300
+ if (this.execution.resources_requests_cpu) {
301
+ _.set(container, 'resources.requests.cpu', this.execution.resources_requests_cpu);
302
+ }
303
+ if (this.execution.resources_limits_cpu) {
304
+ _.set(container, 'resources.limits.cpu', this.execution.resources_limits_cpu);
305
+ }
306
+ } else if (this.execution.cpu || this.terasliceConfig.cpu) {
307
+ // The settings on the executions override the cluster configs
308
+ cpu = this.execution.cpu || this.terasliceConfig.cpu || -1;
309
+ _.set(container, 'resources.requests.cpu', cpu);
310
+ _.set(container, 'resources.limits.cpu', cpu);
311
+ }
312
+ if (this.execution.resources_requests_memory
313
+ || this.execution.resources_limits_memory) {
314
+ _.set(container, 'resources.requests.memory', this.execution.resources_requests_memory);
315
+ _.set(container, 'resources.limits.memory', this.execution.resources_limits_memory);
316
+ maxMemory = this.execution.resources_limits_memory;
317
+ } else if (this.execution.memory || this.terasliceConfig.memory) {
318
+ // The settings on the executions override the cluster configs
319
+ memory = this.execution.memory || this.terasliceConfig.memory || -1;
320
+ _.set(container, 'resources.requests.memory', memory);
321
+ _.set(container, 'resources.limits.memory', memory);
322
+ maxMemory = memory;
323
+ }
277
324
  }
278
325
 
279
326
  if (this.nodeType === 'execution_controller') {
@@ -282,21 +329,17 @@ class K8sResource {
282
329
  || this.terasliceConfig.cpu_execution_controller || -1;
283
330
  memory = this.execution.memory_execution_controller
284
331
  || this.terasliceConfig.memory_execution_controller || -1;
285
- }
286
-
287
- const container = this.resource.spec.template.spec.containers[0];
288
-
289
- if (cpu !== -1) {
290
332
  _.set(container, 'resources.requests.cpu', cpu);
291
333
  _.set(container, 'resources.limits.cpu', cpu);
292
- }
293
-
294
- if (memory !== -1) {
295
334
  _.set(container, 'resources.requests.memory', memory);
296
335
  _.set(container, 'resources.limits.memory', memory);
336
+ maxMemory = memory;
297
337
  }
298
338
 
299
- setMaxOldSpaceViaEnv(container.env, envVars, memory);
339
+ // NOTE: This sucks, this manages the memory env var but it ALSO is
340
+ // responsible for doing the config and execution env var merge, which
341
+ // should NOT be in this function
342
+ setMaxOldSpaceViaEnv(container.env, envVars, maxMemory);
300
343
  }
301
344
 
302
345
  _setTargets() {
@@ -295,6 +295,11 @@ const schema = {
295
295
  default: 'default',
296
296
  format: 'optional_String'
297
297
  },
298
+ kubernetes_priority_class_name: {
299
+ doc: 'Priority class that the Teraslice master, execution controller, and stateful workers should run with',
300
+ default: undefined,
301
+ format: 'optional_String'
302
+ },
298
303
  kubernetes_config_map_name: {
299
304
  doc: 'Specify the name of the Kubernetes ConfigMap used to configure worker pods',
300
305
  default: 'teraslice-worker',
@@ -50,7 +50,7 @@ module.exports = async function analyticsService(context) {
50
50
  time: stats.time[index],
51
51
  memory: stats.memory[index],
52
52
  },
53
- null,
53
+ 'index',
54
54
  esIndex
55
55
  ));
56
56
 
@@ -29,7 +29,7 @@ module.exports = function elasticsearchStorage(backendConfig) {
29
29
  recordType,
30
30
  idField,
31
31
  storageName,
32
- bulkSize = 500,
32
+ bulkSize = 1000,
33
33
  fullResponse = false,
34
34
  logRecord = true,
35
35
  forceRefresh = true,
@@ -161,13 +161,13 @@ module.exports = function elasticsearchStorage(backendConfig) {
161
161
  * index saves a record to elasticsearch with a specified ID.
162
162
  * If the document is already there it will be replaced.
163
163
  */
164
- async function indexWithId(recordId, record, indexArg = indexName, timeout) {
164
+ async function indexWithId(recordId, record, indexArg, timeout) {
165
165
  validateIdAndRecord(recordId, record);
166
166
 
167
167
  logger.trace(`indexWithId call with id: ${recordId}, record`, logRecord ? record : null);
168
168
 
169
169
  const query = {
170
- index: indexArg,
170
+ index: indexArg || indexName,
171
171
  type: recordType,
172
172
  id: recordId,
173
173
  body: record,
@@ -322,14 +322,17 @@ module.exports = function elasticsearchStorage(backendConfig) {
322
322
 
323
323
  const type = _type || 'index';
324
324
 
325
- const indexRequest = {
325
+ const action = {
326
326
  [type]: {
327
327
  _index: indexArg,
328
328
  _type: recordType,
329
329
  }
330
330
  };
331
331
 
332
- bulkQueue.push(indexRequest, record);
332
+ bulkQueue.push({
333
+ action,
334
+ data: type === 'delete' ? undefined : record
335
+ });
333
336
 
334
337
  // We only flush once enough records have accumulated for it to make sense.
335
338
  if (bulkQueue.length >= bulkSize) {
@@ -375,17 +378,7 @@ module.exports = function elasticsearchStorage(backendConfig) {
375
378
  }
376
379
 
377
380
  async function bulkSend(bulkRequest) {
378
- const recordCount = (bulkRequest.length / 2);
379
-
380
- await pRetry(async () => elasticsearch.bulkSend(bulkRequest), {
381
- reason: `Failure to bulk create "${recordType}"`,
382
- logError: logger.warn,
383
- delay: isTest ? 100 : 1000,
384
- backoff: 5,
385
- retries: 100,
386
- });
387
-
388
- return recordCount;
381
+ return elasticsearch.bulkSend(bulkRequest);
389
382
  }
390
383
 
391
384
  async function _flush(shuttingDown = false) {
@@ -60,17 +60,19 @@ async function stateStorage(context) {
60
60
  async function createSlices(exId, slices) {
61
61
  await waitForClient();
62
62
 
63
- const bulkRequest = [];
64
- for (const slice of slices) {
63
+ const bulkRequest = slices.map((slice) => {
65
64
  const { record, index } = _createSliceRecord(exId, slice, SliceState.pending);
66
- bulkRequest.push({
67
- index: {
68
- _index: index,
69
- _type: recordType,
70
- _id: record.slice_id,
65
+ return {
66
+ action: {
67
+ index: {
68
+ _index: index,
69
+ _type: recordType,
70
+ _id: record.slice_id,
71
+ },
71
72
  },
72
- }, record);
73
- }
73
+ data: record
74
+ };
75
+ });
74
76
  return backend.bulkSend(bulkRequest);
75
77
  }
76
78
 
@@ -242,8 +244,8 @@ async function stateStorage(context) {
242
244
  }
243
245
  }
244
246
 
245
- async function search(query, from, size, sort = '_updated:desc', fields) {
246
- return backend.search(query, from, size, sort, fields);
247
+ async function search(query, from, size, sort, fields) {
248
+ return backend.search(query, from, size, sort || '_updated:desc', fields);
247
249
  }
248
250
 
249
251
  async function count(query, from = 0, sort = '_updated:desc') {
@@ -192,7 +192,7 @@ class Worker {
192
192
  this.slicesProcessed += 1;
193
193
  }
194
194
 
195
- async shutdown(block = true, event, shutdownError) {
195
+ async shutdown(block, event, shutdownError) {
196
196
  if (this.isShutdown) return;
197
197
  if (!this.isInitialized) return;
198
198
  const { exId } = this.executionContext;
@@ -202,11 +202,11 @@ class Worker {
202
202
  'worker',
203
203
  `shutdown was called for ${exId}`,
204
204
  'but it was already shutting down',
205
- block ? ', will block until done' : ''
205
+ block !== false ? ', will block until done' : ''
206
206
  ];
207
207
  this.logger.debug(msgs.join(' '));
208
208
 
209
- if (block) {
209
+ if (block !== false) {
210
210
  await waitForWorkerShutdown(this.context, 'worker:shutdown:complete');
211
211
  }
212
212
  return;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "teraslice",
3
3
  "displayName": "Teraslice",
4
- "version": "0.78.0",
4
+ "version": "0.79.0",
5
5
  "description": "Distributed computing platform for processing JSON data",
6
6
  "homepage": "https://github.com/terascope/teraslice#readme",
7
7
  "bugs": {
@@ -33,50 +33,50 @@
33
33
  "test:watch": "ts-scripts test --watch . --"
34
34
  },
35
35
  "resolutions": {
36
- "debug": "^4.3.2",
36
+ "debug": "^4.3.3",
37
37
  "ms": "^2.1.3"
38
38
  },
39
39
  "dependencies": {
40
- "@terascope/elasticsearch-api": "^2.23.5",
41
- "@terascope/job-components": "^0.54.5",
42
- "@terascope/teraslice-messaging": "^0.25.5",
43
- "@terascope/utils": "^0.42.5",
40
+ "@terascope/elasticsearch-api": "^3.0.2",
41
+ "@terascope/job-components": "^0.56.3",
42
+ "@terascope/teraslice-messaging": "^0.27.1",
43
+ "@terascope/utils": "^0.44.1",
44
44
  "async-mutex": "^0.3.2",
45
45
  "barbe": "^3.0.16",
46
- "body-parser": "^1.19.0",
46
+ "body-parser": "^1.19.1",
47
47
  "convict": "^4.4.1",
48
48
  "decompress": "^4.2.1",
49
- "easy-table": "^1.1.1",
49
+ "easy-table": "^1.2.0",
50
50
  "event-loop-stats": "^1.2.0",
51
- "express": "^4.17.1",
52
- "fs-extra": "^9.1.0",
51
+ "express": "^4.17.2",
52
+ "fs-extra": "^10.0.0",
53
53
  "gc-stats": "^1.4.0",
54
- "got": "^11.8.2",
54
+ "got": "^11.8.3",
55
55
  "ip": "^1.1.5",
56
56
  "kubernetes-client": "^9.0.0",
57
57
  "lodash": "^4.17.21",
58
58
  "ms": "^2.1.3",
59
- "nanoid": "^3.1.25",
59
+ "nanoid": "^3.2.0",
60
60
  "porty": "^3.1.1",
61
61
  "semver": "^7.3.5",
62
62
  "socket.io": "^1.7.4",
63
63
  "socket.io-client": "^1.7.4",
64
- "terafoundation": "^0.35.5",
64
+ "terafoundation": "^0.37.1",
65
65
  "uuid": "^8.3.2"
66
66
  },
67
67
  "devDependencies": {
68
- "@terascope/teraslice-op-test-harness": "^1.24.0",
68
+ "@terascope/teraslice-op-test-harness": "^1.24.1",
69
69
  "archiver": "^5.3.0",
70
70
  "bufferstreams": "^3.0.0",
71
71
  "chance": "^1.1.8",
72
72
  "elasticsearch": "^15.4.1",
73
- "got": "^11.8.2",
73
+ "got": "^11.8.3",
74
74
  "jest-fixtures": "^0.6.0",
75
75
  "js-yaml": "^4.1.0",
76
- "nock": "^13.1.3"
76
+ "nock": "^13.2.1"
77
77
  },
78
78
  "engines": {
79
- "node": "^12.20.0 || >=14.17.0",
79
+ "node": "^12.22.0 || >=14.17.0",
80
80
  "yarn": ">=1.16.0"
81
81
  },
82
82
  "publishConfig": {