teraslice 2.11.0 → 2.12.1

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 (118) hide show
  1. package/dist/src/interfaces.js +12 -0
  2. package/dist/src/lib/cluster/cluster_master.js +246 -0
  3. package/dist/src/lib/cluster/node_master.js +355 -0
  4. package/dist/src/lib/cluster/services/api.js +663 -0
  5. package/dist/src/lib/cluster/services/assets.js +226 -0
  6. package/dist/src/lib/cluster/services/cluster/backends/kubernetes/index.js +192 -0
  7. package/dist/src/lib/cluster/services/cluster/backends/kubernetes/k8s.js +481 -0
  8. package/dist/src/lib/cluster/services/cluster/backends/kubernetes/k8sResource.js +414 -0
  9. package/dist/src/lib/cluster/services/cluster/backends/kubernetes/k8sState.js +59 -0
  10. package/dist/src/lib/cluster/services/cluster/backends/kubernetes/utils.js +43 -0
  11. package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/index.js +192 -0
  12. package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/interfaces.js +2 -0
  13. package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8s.js +423 -0
  14. package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8sDeploymentResource.js +60 -0
  15. package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8sJobResource.js +55 -0
  16. package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8sResource.js +359 -0
  17. package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8sServiceResource.js +37 -0
  18. package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8sState.js +60 -0
  19. package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/utils.js +170 -0
  20. package/dist/src/lib/cluster/services/cluster/backends/native/dispatch.js +13 -0
  21. package/dist/src/lib/cluster/services/cluster/backends/native/index.js +526 -0
  22. package/dist/src/lib/cluster/services/cluster/backends/native/messaging.js +547 -0
  23. package/dist/src/lib/cluster/services/cluster/backends/state-utils.js +26 -0
  24. package/dist/src/lib/cluster/services/cluster/index.js +17 -0
  25. package/dist/src/lib/cluster/services/execution.js +435 -0
  26. package/dist/src/lib/cluster/services/index.js +6 -0
  27. package/dist/src/lib/cluster/services/interfaces.js +2 -0
  28. package/dist/src/lib/cluster/services/jobs.js +454 -0
  29. package/dist/src/lib/config/default-sysconfig.js +26 -0
  30. package/dist/src/lib/config/index.js +22 -0
  31. package/dist/src/lib/config/schemas/system.js +360 -0
  32. package/dist/src/lib/storage/analytics.js +86 -0
  33. package/dist/src/lib/storage/assets.js +401 -0
  34. package/dist/src/lib/storage/backends/elasticsearch_store.js +494 -0
  35. package/dist/src/lib/storage/backends/mappings/analytics.js +50 -0
  36. package/dist/src/lib/storage/backends/mappings/asset.js +41 -0
  37. package/dist/src/lib/storage/backends/mappings/ex.js +62 -0
  38. package/dist/src/lib/storage/backends/mappings/job.js +38 -0
  39. package/dist/src/lib/storage/backends/mappings/state.js +38 -0
  40. package/dist/src/lib/storage/backends/s3_store.js +237 -0
  41. package/dist/src/lib/storage/execution.js +300 -0
  42. package/dist/src/lib/storage/index.js +7 -0
  43. package/dist/src/lib/storage/jobs.js +81 -0
  44. package/dist/src/lib/storage/state.js +255 -0
  45. package/dist/src/lib/utils/api_utils.js +157 -0
  46. package/dist/src/lib/utils/asset_utils.js +94 -0
  47. package/dist/src/lib/utils/date_utils.js +52 -0
  48. package/dist/src/lib/utils/encoding_utils.js +27 -0
  49. package/dist/src/lib/utils/events.js +4 -0
  50. package/dist/src/lib/utils/file_utils.js +124 -0
  51. package/dist/src/lib/utils/id_utils.js +15 -0
  52. package/dist/src/lib/utils/port_utils.js +32 -0
  53. package/dist/src/lib/workers/assets/index.js +3 -0
  54. package/dist/src/lib/workers/assets/loader-executable.js +40 -0
  55. package/dist/src/lib/workers/assets/loader.js +73 -0
  56. package/dist/src/lib/workers/assets/spawn.js +55 -0
  57. package/dist/src/lib/workers/context/execution-context.js +12 -0
  58. package/dist/src/lib/workers/context/terafoundation-context.js +8 -0
  59. package/dist/src/lib/workers/execution-controller/execution-analytics.js +188 -0
  60. package/dist/src/lib/workers/execution-controller/index.js +1024 -0
  61. package/dist/src/lib/workers/execution-controller/recovery.js +151 -0
  62. package/dist/src/lib/workers/execution-controller/scheduler.js +390 -0
  63. package/dist/src/lib/workers/execution-controller/slice-analytics.js +96 -0
  64. package/dist/src/lib/workers/helpers/job.js +80 -0
  65. package/dist/src/lib/workers/helpers/op-analytics.js +22 -0
  66. package/dist/src/lib/workers/helpers/terafoundation.js +34 -0
  67. package/dist/src/lib/workers/helpers/worker-shutdown.js +169 -0
  68. package/dist/src/lib/workers/metrics/index.js +108 -0
  69. package/dist/src/lib/workers/worker/index.js +378 -0
  70. package/dist/src/lib/workers/worker/slice.js +122 -0
  71. package/dist/test/config/schemas/system_schema-spec.js +37 -0
  72. package/dist/test/lib/cluster/services/cluster/backends/kubernetes/k8s-spec.js +316 -0
  73. package/dist/test/lib/cluster/services/cluster/backends/kubernetes/k8sResource-spec.js +795 -0
  74. package/dist/test/lib/cluster/services/cluster/backends/kubernetes/k8sState-multicluster-spec.js +67 -0
  75. package/dist/test/lib/cluster/services/cluster/backends/kubernetes/k8sState-spec.js +84 -0
  76. package/dist/test/lib/cluster/services/cluster/backends/kubernetes/utils-spec.js +132 -0
  77. package/dist/test/lib/cluster/services/cluster/backends/kubernetes/v2/k8s-v2-spec.js +455 -0
  78. package/dist/test/lib/cluster/services/cluster/backends/kubernetes/v2/k8sResource-v2-spec.js +818 -0
  79. package/dist/test/lib/cluster/services/cluster/backends/kubernetes/v2/k8sState-multicluster-v2-spec.js +67 -0
  80. package/dist/test/lib/cluster/services/cluster/backends/kubernetes/v2/k8sState-v2-spec.js +84 -0
  81. package/dist/test/lib/cluster/services/cluster/backends/kubernetes/v2/utils-v2-spec.js +320 -0
  82. package/dist/test/lib/cluster/services/cluster/backends/state-utils-spec.js +37 -0
  83. package/dist/test/node_master-spec.js +188 -0
  84. package/dist/test/services/api-spec.js +80 -0
  85. package/dist/test/services/assets-spec.js +158 -0
  86. package/dist/test/services/messaging-spec.js +440 -0
  87. package/dist/test/storage/assets_storage-spec.js +95 -0
  88. package/dist/test/storage/s3_store-spec.js +138 -0
  89. package/dist/test/test.config.js +8 -0
  90. package/dist/test/test.setup.js +6 -0
  91. package/dist/test/utils/api_utils-spec.js +86 -0
  92. package/dist/test/utils/asset_utils-spec.js +141 -0
  93. package/dist/test/utils/elastic_utils-spec.js +25 -0
  94. package/dist/test/workers/execution-controller/execution-controller-spec.js +371 -0
  95. package/dist/test/workers/execution-controller/execution-special-test-cases-spec.js +520 -0
  96. package/dist/test/workers/execution-controller/execution-test-cases-spec.js +338 -0
  97. package/dist/test/workers/execution-controller/recovery-spec.js +160 -0
  98. package/dist/test/workers/execution-controller/scheduler-spec.js +249 -0
  99. package/dist/test/workers/execution-controller/slice-analytics-spec.js +121 -0
  100. package/dist/test/workers/fixtures/ops/example-op/processor.js +20 -0
  101. package/dist/test/workers/fixtures/ops/example-op/schema.js +19 -0
  102. package/dist/test/workers/fixtures/ops/example-reader/fetcher.js +20 -0
  103. package/dist/test/workers/fixtures/ops/example-reader/schema.js +41 -0
  104. package/dist/test/workers/fixtures/ops/example-reader/slicer.js +37 -0
  105. package/dist/test/workers/fixtures/ops/new-op/processor.js +29 -0
  106. package/dist/test/workers/fixtures/ops/new-op/schema.js +18 -0
  107. package/dist/test/workers/fixtures/ops/new-reader/fetcher.js +19 -0
  108. package/dist/test/workers/fixtures/ops/new-reader/schema.js +23 -0
  109. package/dist/test/workers/fixtures/ops/new-reader/slicer.js +13 -0
  110. package/dist/test/workers/helpers/configs.js +130 -0
  111. package/dist/test/workers/helpers/execution-controller-helper.js +49 -0
  112. package/dist/test/workers/helpers/index.js +5 -0
  113. package/dist/test/workers/helpers/test-context.js +210 -0
  114. package/dist/test/workers/helpers/zip-directory.js +25 -0
  115. package/dist/test/workers/worker/slice-spec.js +333 -0
  116. package/dist/test/workers/worker/worker-spec.js +356 -0
  117. package/package.json +94 -94
  118. package/service.js +0 -0
@@ -0,0 +1,494 @@
1
+ import ms from 'ms';
2
+ import { TSError, parseError, isTest, pDelay, pRetry, logError, pWhile, isString, getTypeOf, get, random, isInteger } from '@terascope/utils';
3
+ import elasticsearchApi from '@terascope/elasticsearch-api';
4
+ import { getClient } from '@terascope/job-components';
5
+ import { makeLogger } from '../../workers/helpers/terafoundation.js';
6
+ import { timeseriesIndex } from '../../utils/date_utils.js';
7
+ import analyticsSchema from './mappings/analytics.js';
8
+ import assetSchema from './mappings/asset.js';
9
+ import executionSchema from './mappings/ex.js';
10
+ import jobsSchema from './mappings/job.js';
11
+ import stateSchema from './mappings/state.js';
12
+ function validateId(recordId, recordType) {
13
+ if (!recordId || !isString(recordId)) {
14
+ throw new TSError(`Invalid ${recordType} id given ${getTypeOf(recordId)}`, {
15
+ statusCode: 422
16
+ });
17
+ }
18
+ }
19
+ function validateIdAndRecord(recordId, record, recordType, idField) {
20
+ validateId(recordId, recordType);
21
+ const id = record[idField];
22
+ if (id && id !== recordId) {
23
+ throw new TSError(`${recordType}.${idField} doesn't match request id`, {
24
+ statusCode: 406
25
+ });
26
+ }
27
+ }
28
+ // TODO: fix types here
29
+ function _getTimeout(timeout) {
30
+ if (isInteger(timeout)) {
31
+ // don't allow a timeout of less than 1 second
32
+ if (timeout <= 1000)
33
+ return undefined;
34
+ return ms(timeout);
35
+ }
36
+ if (isString(timeout)) {
37
+ return timeout;
38
+ }
39
+ return undefined;
40
+ }
41
+ // TODO: type this better
42
+ export class TerasliceElasticsearchStorage {
43
+ context;
44
+ logger;
45
+ recordType;
46
+ // TODO: should this be here?
47
+ defaultIndexName;
48
+ storageName;
49
+ flushInterval;
50
+ isShuttingDown = false;
51
+ // flag to know if already in a bulk call
52
+ savingBulk = false;
53
+ // Buffer to build up bulk requests. TODO: fix type
54
+ bulkQueue = [];
55
+ idField;
56
+ options;
57
+ mapping;
58
+ api;
59
+ constructor(backendConfig) {
60
+ const { context, indexName, recordType, idField, storageName, bulkSize = 1000, fullResponse = false, logRecord = true, forceRefresh = true, logger } = backendConfig;
61
+ this.context = context;
62
+ this.storageName = storageName;
63
+ this.logger = logger ?? makeLogger(context, 'elasticsearch_backend', { storageName });
64
+ this.recordType = recordType;
65
+ if (recordType === 'analytics') {
66
+ this.mapping = analyticsSchema;
67
+ }
68
+ else if (recordType === 'asset') {
69
+ this.mapping = assetSchema;
70
+ }
71
+ else if (recordType === 'ex') {
72
+ this.mapping = executionSchema;
73
+ }
74
+ else if (recordType === 'job') {
75
+ this.mapping = jobsSchema;
76
+ }
77
+ else if (recordType === 'state') {
78
+ this.mapping = stateSchema;
79
+ }
80
+ else {
81
+ throw new Error(`Could not find mapping for recordType: ${recordType}`);
82
+ }
83
+ const config = this.context.sysconfig.teraslice;
84
+ const indexSettings = get(config, ['index_settings', this.storageName], {
85
+ number_of_shards: 5,
86
+ number_of_replicas: 1,
87
+ });
88
+ this.mapping.settings = {
89
+ 'index.number_of_shards': indexSettings.number_of_shards,
90
+ 'index.number_of_replicas': indexSettings.number_of_replicas,
91
+ };
92
+ this.defaultIndexName = indexName;
93
+ this.idField = idField;
94
+ this.options = {
95
+ bulkSize,
96
+ fullResponse,
97
+ logRecord,
98
+ forceRefresh
99
+ };
100
+ }
101
+ async initialize() {
102
+ const config = this.context.sysconfig.teraslice;
103
+ const isMultiIndex = this.defaultIndexName[this.defaultIndexName.length - 1] === '*';
104
+ let newIndex = this.defaultIndexName;
105
+ if (isMultiIndex) {
106
+ // @ts-expect-error TODO: fix this
107
+ const storeType = this.defaultIndexName.match(/__(.*)\*/)[1];
108
+ const timeseriesFormat = config.index_rollover_frequency[storeType];
109
+ const nameSize = this.defaultIndexName.length - 1;
110
+ newIndex = timeseriesIndex(timeseriesFormat, this.defaultIndexName.slice(0, nameSize)).index;
111
+ }
112
+ const clientName = JSON.stringify({
113
+ connection: config.state.connection,
114
+ index: this.defaultIndexName,
115
+ });
116
+ const connectionConfig = Object.assign({}, config.state);
117
+ if (connectionConfig.connection_cache == null) {
118
+ connectionConfig.connection_cache = true;
119
+ }
120
+ const { connection } = config.state;
121
+ const options = {
122
+ full_response: !!this.options.fullResponse,
123
+ connection,
124
+ };
125
+ await pWhile(async () => {
126
+ try {
127
+ const client = await getClient(this.context, connectionConfig, 'elasticsearch-next');
128
+ this.api = elasticsearchApi(client, this.logger, options);
129
+ await this._createIndex(newIndex);
130
+ await this.api.isAvailable(newIndex, this.recordType);
131
+ return true;
132
+ }
133
+ catch (err) {
134
+ const error = new TSError(err, {
135
+ reason: `Failure initializing ${this.recordType} index: ${this.defaultIndexName}`,
136
+ });
137
+ if (error.statusCode >= 400 && error.statusCode < 500) {
138
+ throw error;
139
+ }
140
+ logError(this.logger, error, `Failed attempt connecting to elasticsearch: ${clientName} (will retry)`);
141
+ await pDelay(isTest ? 0 : random(2000, 4000));
142
+ return false;
143
+ }
144
+ });
145
+ // Periodically flush the bulkQueue so we don't end up with cached data lingering.
146
+ this.flushInterval = setInterval(() => {
147
+ // TODO: this might be undefined
148
+ this._flush().catch((err) => {
149
+ logError(this.logger, err, 'background flush failure');
150
+ return null;
151
+ });
152
+ // stager the interval to avoid collisions
153
+ }, random(9000, 11000));
154
+ }
155
+ async get(recordId, index = this.defaultIndexName, fields) {
156
+ validateId(recordId, this.recordType);
157
+ this.logger.trace(`getting record id: ${recordId}`);
158
+ const query = {
159
+ index,
160
+ type: this.recordType,
161
+ id: recordId,
162
+ };
163
+ if (fields) {
164
+ if (!this.api.isElasticsearch6()) {
165
+ query._source_includes = fields;
166
+ }
167
+ else {
168
+ // @ts-expect-error backwards compatible
169
+ query._sourceInclude = fields;
170
+ }
171
+ }
172
+ return this.api.get(query);
173
+ }
174
+ async search(query, from = 0, size = 10000, sort, fields, index = this.defaultIndexName) {
175
+ if (from != null && !isInteger(from)) {
176
+ throw new Error(`from parameter must be a integer, got ${from}`);
177
+ }
178
+ if (size != null && !isInteger(size)) {
179
+ throw new Error(`size parameter must be a integer, got ${size}`);
180
+ }
181
+ if (sort != null && !isString(sort)) {
182
+ throw new Error(`sort parameter must be a string, got ${sort}`);
183
+ }
184
+ const esQuery = {
185
+ index,
186
+ from,
187
+ size,
188
+ type: this.recordType,
189
+ sort,
190
+ };
191
+ if (typeof query === 'string') {
192
+ esQuery.q = query;
193
+ }
194
+ else {
195
+ esQuery.body = query;
196
+ }
197
+ if (fields) {
198
+ if (!this.api.isElasticsearch6()) {
199
+ esQuery._source_includes = fields;
200
+ }
201
+ else {
202
+ // @ts-expect-error backwards compatible
203
+ esQuery._sourceInclude = fields;
204
+ }
205
+ }
206
+ return this.api.search(esQuery);
207
+ }
208
+ /*
209
+ * index saves a record to elasticsearch allowing automatic
210
+ * ID creation
211
+ */
212
+ async index(record, indexArg = this.defaultIndexName) {
213
+ this.logger.trace('indexing record', this.options.logRecord ? record : undefined);
214
+ const query = {
215
+ index: indexArg,
216
+ type: this.recordType,
217
+ body: record,
218
+ refresh: this.options.forceRefresh,
219
+ };
220
+ return this.api.index(query);
221
+ }
222
+ /*
223
+ * index saves a record to elasticsearch with a specified ID.
224
+ * If the document is already there it will be replaced.
225
+ */
226
+ async indexWithId(recordId, record, index = this.defaultIndexName, timeout) {
227
+ validateIdAndRecord(recordId, record, this.recordType, this.idField);
228
+ this.logger.trace(`indexWithId call with id: ${recordId}, record`, this.options.logRecord ? record : null);
229
+ const query = {
230
+ index,
231
+ type: this.recordType,
232
+ id: recordId,
233
+ body: record,
234
+ refresh: this.options.forceRefresh,
235
+ timeout: _getTimeout(timeout)
236
+ };
237
+ return this.api.indexWithId(query);
238
+ }
239
+ /*
240
+ * Create saves a record to elasticsearch under the provided id.
241
+ * If the record already exists it will not be inserted.
242
+ */
243
+ async create(record, index = this.defaultIndexName) {
244
+ this.logger.trace('creating record', this.options.logRecord ? record : null);
245
+ const query = {
246
+ index,
247
+ type: this.recordType,
248
+ id: record[this.idField],
249
+ body: record,
250
+ refresh: this.options.forceRefresh,
251
+ };
252
+ return this.api.create(query);
253
+ }
254
+ async count(query, from, sort, index = this.defaultIndexName) {
255
+ if (from != null && !isInteger(from)) {
256
+ throw new Error(`from parameter must be a integer, got ${from}`);
257
+ }
258
+ if (sort != null && !isString(sort)) {
259
+ throw new Error(`sort parameter must be a string, got ${sort}`);
260
+ }
261
+ // TODO: check from
262
+ const esQuery = {
263
+ index,
264
+ type: this.recordType,
265
+ // @ts-expect-error
266
+ from,
267
+ sort,
268
+ };
269
+ if (isString(query)) {
270
+ esQuery.q = query;
271
+ }
272
+ else {
273
+ esQuery.body = query;
274
+ }
275
+ return this.api.count(esQuery);
276
+ }
277
+ async update(recordId, updateSpec, index = this.defaultIndexName) {
278
+ validateIdAndRecord(recordId, updateSpec, this.recordType, this.idField);
279
+ this.logger.trace(`updating record ${recordId}, `, this.options.logRecord ? updateSpec : null);
280
+ const query = {
281
+ index,
282
+ type: this.recordType,
283
+ id: recordId,
284
+ body: {
285
+ doc: updateSpec,
286
+ },
287
+ refresh: this.options.forceRefresh,
288
+ // TODO: check this retry
289
+ retry_on_conflict: 3,
290
+ };
291
+ return this.api.update(query);
292
+ }
293
+ async updatePartial(recordId, applyChanges, index = this.defaultIndexName) {
294
+ if (typeof applyChanges !== 'function') {
295
+ throw new Error('Update Partial expected a applyChanges function');
296
+ }
297
+ validateId(recordId, this.recordType);
298
+ const getParams = {
299
+ index,
300
+ type: this.recordType,
301
+ id: recordId,
302
+ };
303
+ const existing = await pRetry(() => this.api.get(getParams, true), {
304
+ matches: ['no_shard_available_action_exception'],
305
+ delay: 1000,
306
+ retries: 10,
307
+ backoff: 5
308
+ });
309
+ const doc = await applyChanges(Object.assign({}, existing._source));
310
+ this.logger.trace(`updating partial record ${recordId}, `, this.options.logRecord ? doc : null);
311
+ validateIdAndRecord(recordId, doc, this.recordType, this.idField);
312
+ const query = {
313
+ index,
314
+ type: this.recordType,
315
+ id: recordId,
316
+ body: doc,
317
+ refresh: this.options.forceRefresh,
318
+ };
319
+ if (!this.api.isElasticsearch6()) {
320
+ query.if_seq_no = existing._seq_no;
321
+ query.if_primary_term = existing._primary_term;
322
+ }
323
+ else {
324
+ query.version = existing._version;
325
+ }
326
+ try {
327
+ await this.api.indexWithId(query);
328
+ return doc;
329
+ }
330
+ catch (err) {
331
+ // if there is a version conflict
332
+ if (err.statusCode === 409 && err.message.includes('version conflict')) {
333
+ this.logger.debug({ error: err }, `version conflict when updating "${recordId}" (${this.recordType})`);
334
+ return this.updatePartial(recordId, applyChanges, index);
335
+ }
336
+ throw new TSError(err);
337
+ }
338
+ }
339
+ async remove(recordId, index = this.defaultIndexName) {
340
+ validateId(recordId, this.recordType);
341
+ this.logger.trace(`removing record ${recordId}`);
342
+ const query = {
343
+ index,
344
+ type: this.recordType,
345
+ id: recordId,
346
+ refresh: this.options.forceRefresh,
347
+ };
348
+ return this.api.remove(query);
349
+ }
350
+ async bulk(record, type = 'index', index = this.defaultIndexName) {
351
+ if (this.isShuttingDown) {
352
+ throw new TSError('Unable to send bulk record after shutdown', {
353
+ context: {
354
+ recordType: this.recordType,
355
+ record,
356
+ },
357
+ });
358
+ }
359
+ const action = {
360
+ [type]: {
361
+ _index: index,
362
+ _type: this.recordType,
363
+ }
364
+ };
365
+ this.bulkQueue.push({
366
+ action,
367
+ data: type === 'delete' ? undefined : record
368
+ });
369
+ // We only flush once enough records have accumulated for it to make sense.
370
+ if (this.bulkQueue.length >= this.options.bulkSize) {
371
+ this.logger.trace(`flushing bulk queue ${this.bulkQueue.length}`);
372
+ return this._flush();
373
+ }
374
+ // Bulk saving is a background operation so we don't have
375
+ // anything meaningful to return.
376
+ return Promise.resolve(true);
377
+ }
378
+ _destroy(err) {
379
+ this.bulkQueue = [];
380
+ this.isShuttingDown = true;
381
+ if (err) {
382
+ throw err;
383
+ }
384
+ return true;
385
+ }
386
+ async shutdown(forceShutdown = false) {
387
+ const startTime = Date.now();
388
+ this.logger.trace(`shutdown store, took ${ms(Date.now() - startTime)}`);
389
+ clearInterval(this.flushInterval);
390
+ if (forceShutdown !== true) {
391
+ return this._flush(true);
392
+ }
393
+ const destroy = this._destroy.bind(this);
394
+ const timeout = this.context.sysconfig.teraslice.shutdown_timeout;
395
+ this.logger.trace(`attempting to shutdown, will destroy in ${timeout}`);
396
+ setTimeout(destroy, timeout).unref();
397
+ try {
398
+ await this._flush(true);
399
+ this._destroy();
400
+ }
401
+ catch (err) {
402
+ this._destroy(err);
403
+ }
404
+ }
405
+ async bulkSend(bulkRequest) {
406
+ return this.api.bulkSend(bulkRequest);
407
+ }
408
+ async _flush(shuttingDown = false) {
409
+ if (!this.bulkQueue.length)
410
+ return;
411
+ if (!shuttingDown && this.savingBulk)
412
+ return;
413
+ this.savingBulk = true;
414
+ const bulkRequest = this.bulkQueue.slice();
415
+ this.bulkQueue = [];
416
+ try {
417
+ const recordCount = await this.bulkSend(bulkRequest);
418
+ const extraMsg = shuttingDown ? ', on shutdown' : '';
419
+ this.logger.debug(`flushed ${recordCount}${extraMsg} records to index ${this.defaultIndexName}`);
420
+ }
421
+ finally {
422
+ this.savingBulk = false;
423
+ }
424
+ }
425
+ async sendTemplate(mapping) {
426
+ if (mapping.template) {
427
+ const clusterName = this.context.sysconfig.teraslice.name;
428
+ const name = `${clusterName}_${this.recordType}_template`;
429
+ // setting template name to reflect current teraslice instance name to help prevent
430
+ // conflicts with differing versions of teraslice with same elastic db
431
+ if (mapping.template) {
432
+ if (!mapping.template.match(clusterName)) {
433
+ mapping.template = `${clusterName}${mapping.template}`;
434
+ }
435
+ }
436
+ return this.putTemplate(mapping, name);
437
+ }
438
+ return Promise.resolve(true);
439
+ }
440
+ async _createIndex(index = this.defaultIndexName) {
441
+ // @ts-expect-error TODO: check type missing id
442
+ const existQuery = { index };
443
+ const exists = await this.api.indexExists(existQuery);
444
+ if (!exists) {
445
+ // Make sure the index exists before we do anything else.
446
+ const createQuery = {
447
+ index,
448
+ body: this.mapping,
449
+ };
450
+ try {
451
+ await this.sendTemplate(this.mapping);
452
+ return await this.api.indexCreate(createQuery);
453
+ }
454
+ catch (err) {
455
+ // It's not really an error if it's just that the index is already there
456
+ if (parseError(err).includes('already_exists_exception')) {
457
+ return true;
458
+ }
459
+ const error = new TSError(err, {
460
+ reason: `Could not create index: ${index}`,
461
+ });
462
+ throw error;
463
+ }
464
+ }
465
+ // Index already exists. nothing to do.
466
+ return true;
467
+ }
468
+ async refresh(index = this.defaultIndexName) {
469
+ const query = { index };
470
+ return this.api.indexRefresh(query);
471
+ }
472
+ // TODO: fix type here
473
+ async putTemplate(template, name) {
474
+ return this.api.putTemplate(template, name);
475
+ }
476
+ verifyClient() {
477
+ if (this.isShuttingDown)
478
+ return false;
479
+ return this.api.verifyClient();
480
+ }
481
+ async waitForClient() {
482
+ if (this.api.verifyClient())
483
+ return;
484
+ await pWhile(async () => {
485
+ if (this.isShuttingDown)
486
+ throw new Error('Elasticsearch store is shutdown');
487
+ if (this.api.verifyClient())
488
+ return true;
489
+ await pDelay(100);
490
+ return false;
491
+ });
492
+ }
493
+ }
494
+ //# sourceMappingURL=elasticsearch_store.js.map
@@ -0,0 +1,50 @@
1
+ export default {
2
+ template: '__analytics*',
3
+ mappings: {
4
+ analytics: {
5
+ _all: {
6
+ enabled: false
7
+ },
8
+ dynamic: false,
9
+ properties: {
10
+ ex_id: {
11
+ type: 'keyword'
12
+ },
13
+ job_id: {
14
+ type: 'keyword'
15
+ },
16
+ worker_id: {
17
+ type: 'keyword'
18
+ },
19
+ slice_id: {
20
+ type: 'keyword'
21
+ },
22
+ slicer_id: {
23
+ type: 'keyword'
24
+ },
25
+ op: {
26
+ type: 'keyword'
27
+ },
28
+ order: {
29
+ type: 'integer'
30
+ },
31
+ count: {
32
+ type: 'integer'
33
+ },
34
+ state: {
35
+ type: 'keyword'
36
+ },
37
+ time: {
38
+ type: 'integer'
39
+ },
40
+ memory: {
41
+ type: 'long'
42
+ },
43
+ '@timestamp': {
44
+ type: 'date'
45
+ }
46
+ }
47
+ }
48
+ }
49
+ };
50
+ //# sourceMappingURL=analytics.js.map
@@ -0,0 +1,41 @@
1
+ export default {
2
+ mappings: {
3
+ asset: {
4
+ _all: {
5
+ enabled: false
6
+ },
7
+ dynamic: false,
8
+ properties: {
9
+ blob: {
10
+ type: 'binary',
11
+ doc_values: false
12
+ },
13
+ name: {
14
+ type: 'keyword'
15
+ },
16
+ version: {
17
+ type: 'keyword'
18
+ },
19
+ id: {
20
+ type: 'keyword'
21
+ },
22
+ description: {
23
+ type: 'keyword'
24
+ },
25
+ arch: {
26
+ type: 'keyword'
27
+ },
28
+ platform: {
29
+ type: 'keyword'
30
+ },
31
+ node_version: {
32
+ type: 'integer'
33
+ },
34
+ _created: {
35
+ type: 'date'
36
+ }
37
+ }
38
+ }
39
+ }
40
+ };
41
+ //# sourceMappingURL=asset.js.map
@@ -0,0 +1,62 @@
1
+ export default {
2
+ mappings: {
3
+ ex: {
4
+ _all: {
5
+ enabled: false
6
+ },
7
+ dynamic: false,
8
+ properties: {
9
+ active: {
10
+ type: 'boolean'
11
+ },
12
+ job_id: {
13
+ type: 'keyword'
14
+ },
15
+ ex_id: {
16
+ type: 'keyword'
17
+ },
18
+ _context: {
19
+ type: 'keyword'
20
+ },
21
+ _status: {
22
+ type: 'keyword'
23
+ },
24
+ _has_errors: {
25
+ type: 'keyword'
26
+ },
27
+ slicer_hostname: {
28
+ type: 'keyword'
29
+ },
30
+ slicer_port: {
31
+ type: 'keyword'
32
+ },
33
+ recovered_execution: {
34
+ type: 'keyword'
35
+ },
36
+ recovered_slice_type: {
37
+ type: 'keyword'
38
+ },
39
+ metadata: {
40
+ type: 'object',
41
+ enabled: false
42
+ },
43
+ _slicer_stats: {
44
+ type: 'object'
45
+ },
46
+ _created: {
47
+ type: 'date'
48
+ },
49
+ _updated: {
50
+ type: 'date'
51
+ },
52
+ _deleted: {
53
+ type: 'boolean'
54
+ },
55
+ _deleted_on: {
56
+ type: 'date'
57
+ }
58
+ }
59
+ }
60
+ }
61
+ };
62
+ //# sourceMappingURL=ex.js.map
@@ -0,0 +1,38 @@
1
+ export default {
2
+ settings: {
3
+ 'index.number_of_shards': 5,
4
+ 'index.number_of_replicas': 1
5
+ },
6
+ mappings: {
7
+ job: {
8
+ _all: {
9
+ enabled: false
10
+ },
11
+ dynamic: false,
12
+ properties: {
13
+ active: {
14
+ type: 'boolean'
15
+ },
16
+ job_id: {
17
+ type: 'keyword'
18
+ },
19
+ _context: {
20
+ type: 'keyword'
21
+ },
22
+ _created: {
23
+ type: 'date'
24
+ },
25
+ _updated: {
26
+ type: 'date'
27
+ },
28
+ _deleted: {
29
+ type: 'boolean'
30
+ },
31
+ _deleted_on: {
32
+ type: 'date'
33
+ }
34
+ }
35
+ }
36
+ }
37
+ };
38
+ //# sourceMappingURL=job.js.map