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,303 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const defaultsDeep = require('lodash/defaultsDeep');
|
|
4
|
-
const {
|
|
5
|
-
TSError,
|
|
6
|
-
uniq,
|
|
7
|
-
get,
|
|
8
|
-
cloneDeep,
|
|
9
|
-
isEmpty,
|
|
10
|
-
getTypeOf,
|
|
11
|
-
isString,
|
|
12
|
-
} = require('@terascope/utils');
|
|
13
|
-
const { JobValidator } = require('@terascope/job-components');
|
|
14
|
-
const { makeLogger } = require('../../workers/helpers/terafoundation');
|
|
15
|
-
const spawnAssetsLoader = require('../../workers/assets/spawn');
|
|
16
|
-
const { terasliceOpPath } = require('../../config');
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* New execution result
|
|
20
|
-
* @typedef NewExecutionResult
|
|
21
|
-
* @property {string} job_id
|
|
22
|
-
* @property {string} ex_id
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
module.exports = function jobsService(context) {
|
|
26
|
-
let executionService;
|
|
27
|
-
let exStore;
|
|
28
|
-
let jobStore;
|
|
29
|
-
|
|
30
|
-
const logger = makeLogger(context, 'jobs_service');
|
|
31
|
-
|
|
32
|
-
const jobValidator = new JobValidator(context, {
|
|
33
|
-
terasliceOpPath,
|
|
34
|
-
assetPath: get(context, 'sysconfig.teraslice.assets_directory'),
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Validate the job spec
|
|
39
|
-
*
|
|
40
|
-
* @returns {Promise<import('@terascope/job-components').ValidatedJobConfig>}
|
|
41
|
-
*/
|
|
42
|
-
async function _validateJobSpec(jobSpec) {
|
|
43
|
-
const parsedAssetJob = await _ensureAssets(cloneDeep(jobSpec));
|
|
44
|
-
const validJob = await jobValidator.validateConfig(parsedAssetJob);
|
|
45
|
-
return validJob;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async function submitJob(jobSpec, shouldRun) {
|
|
49
|
-
if (jobSpec.job_id) {
|
|
50
|
-
throw new TSError('Job cannot include a job_id on submit', {
|
|
51
|
-
statusCode: 422,
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const validJob = await _validateJobSpec(jobSpec);
|
|
56
|
-
const job = await jobStore.create(jobSpec);
|
|
57
|
-
if (!shouldRun) {
|
|
58
|
-
return { job_id: job.job_id };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const exConfig = Object.assign({}, jobSpec, validJob, {
|
|
62
|
-
job_id: job.job_id
|
|
63
|
-
});
|
|
64
|
-
return executionService.createExecutionContext(exConfig);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Sets the `active` property on the job to `true` or `false`.
|
|
69
|
-
* @param {string} jobId
|
|
70
|
-
* @param {boolean} activeState
|
|
71
|
-
*/
|
|
72
|
-
async function setActiveState(jobId, activeState) {
|
|
73
|
-
const job = await jobStore.get(jobId);
|
|
74
|
-
if (activeState === true) {
|
|
75
|
-
job.active = true;
|
|
76
|
-
} else {
|
|
77
|
-
job.active = false;
|
|
78
|
-
}
|
|
79
|
-
logger.info(`Setting jobId: ${jobId} to active: ${activeState}`);
|
|
80
|
-
return updateJob(jobId, job);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async function updateJob(jobId, jobSpec) {
|
|
84
|
-
await _validateJobSpec(jobSpec);
|
|
85
|
-
const originalJob = await jobStore.get(jobId);
|
|
86
|
-
return jobStore.update(jobId, Object.assign({}, jobSpec, {
|
|
87
|
-
_created: originalJob._created
|
|
88
|
-
}));
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Start a Job
|
|
93
|
-
*
|
|
94
|
-
* @param {string} jobId
|
|
95
|
-
* @returns {Promise<NewExecutionResult>}
|
|
96
|
-
*/
|
|
97
|
-
async function startJob(jobId) {
|
|
98
|
-
const activeExecution = await _getActiveExecution(jobId, true);
|
|
99
|
-
|
|
100
|
-
// searching for an active execution, if there is then we reject
|
|
101
|
-
if (activeExecution) {
|
|
102
|
-
throw new TSError(`Job ${jobId} is currently running, cannot have the same job concurrently running`, {
|
|
103
|
-
statusCode: 409
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const jobSpec = await jobStore.get(jobId);
|
|
108
|
-
const validJob = await _validateJobSpec(jobSpec);
|
|
109
|
-
|
|
110
|
-
if (validJob.autorecover) {
|
|
111
|
-
return _recoverValidJob(validJob);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return executionService.createExecutionContext(validJob);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Recover a job using the valid configuration
|
|
119
|
-
*
|
|
120
|
-
* @private
|
|
121
|
-
* @param {import('@terascope/job-components').ValidatedJobConfig} validJob
|
|
122
|
-
* @param {import('@terascope/job-components').RecoveryCleanupType} [cleanupType]
|
|
123
|
-
* @returns {Promise<NewExecutionResult>}
|
|
124
|
-
*/
|
|
125
|
-
async function _recoverValidJob(validJob, cleanupType) {
|
|
126
|
-
const recoverFrom = await getLatestExecution(validJob.job_id, undefined, true);
|
|
127
|
-
|
|
128
|
-
// if there isn't an execution and autorecover is true
|
|
129
|
-
// create a new execution else throw
|
|
130
|
-
if (!recoverFrom) {
|
|
131
|
-
if (validJob.autorecover) {
|
|
132
|
-
return executionService.createExecutionContext(validJob);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
throw new TSError(`Job ${validJob.job_id} is missing an execution to recover from`, {
|
|
136
|
-
statusCode: 404
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (validJob.slicers !== recoverFrom.slicers) {
|
|
141
|
-
const changedFrom = `from ${recoverFrom.slicers} to ${validJob.slicers}`;
|
|
142
|
-
logger.warn(`recovery for job ${recoverFrom.job_id} changed slicers ${changedFrom}`);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return executionService.recoverExecution(
|
|
146
|
-
// apply the latest job config changes
|
|
147
|
-
defaultsDeep({}, validJob, recoverFrom),
|
|
148
|
-
cleanupType
|
|
149
|
-
);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Recover a job, applied the last changes to the prev execution
|
|
154
|
-
*
|
|
155
|
-
* @param {string} jobId
|
|
156
|
-
* @param {import('@terascope/job-components').RecoveryCleanupType} [cleanupType]
|
|
157
|
-
* @returns {Promise<NewExecutionResult>}
|
|
158
|
-
*/
|
|
159
|
-
async function recoverJob(jobId, cleanupType) {
|
|
160
|
-
// we need to do validations since the job config could change between recovery
|
|
161
|
-
const jobSpec = await jobStore.get(jobId);
|
|
162
|
-
const validJob = await _validateJobSpec(jobSpec);
|
|
163
|
-
return _recoverValidJob(validJob, cleanupType);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
async function pauseJob(jobId) {
|
|
167
|
-
return getLatestExecutionId(jobId).then((exId) => executionService.pauseExecution(exId));
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
async function resumeJob(jobId) {
|
|
171
|
-
return getLatestExecutionId(jobId).then((exId) => executionService.resumeExecution(exId));
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Get the latest execution
|
|
176
|
-
*
|
|
177
|
-
* @param {string} jobId
|
|
178
|
-
* @param {string} [query]
|
|
179
|
-
* @param {boolean=false} [allowZeroResults]
|
|
180
|
-
* @returns {Promise<import('@terascope/job-components').ExecutionConfig>}
|
|
181
|
-
*/
|
|
182
|
-
async function getLatestExecution(jobId, query, allowZeroResults = false) {
|
|
183
|
-
if (!jobId || !isString(jobId)) {
|
|
184
|
-
throw new TSError(`Invalid job id, got ${getTypeOf(jobId)}`);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const ex = await exStore.search(
|
|
188
|
-
query || `job_id: "${jobId}"`, null, 1, '_created:desc'
|
|
189
|
-
);
|
|
190
|
-
|
|
191
|
-
if (!allowZeroResults && !ex.length) {
|
|
192
|
-
throw new TSError(`No execution was found for job ${jobId}`, {
|
|
193
|
-
statusCode: 404
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
return ex[0];
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Get the active execution
|
|
201
|
-
*
|
|
202
|
-
* @param {string} jobId
|
|
203
|
-
* @param {boolean} [allowZeroResults]
|
|
204
|
-
* @returns {Promise<import('@terascope/job-components').ExecutionConfig>}
|
|
205
|
-
*/
|
|
206
|
-
async function _getActiveExecution(jobId, allowZeroResults) {
|
|
207
|
-
const str = exStore
|
|
208
|
-
.getTerminalStatuses()
|
|
209
|
-
.map((state) => ` _status:"${state}"`)
|
|
210
|
-
.join(' OR ');
|
|
211
|
-
const query = `job_id:"${jobId}" AND _context:ex NOT (${str.trim()})`;
|
|
212
|
-
return getLatestExecution(jobId, query, allowZeroResults);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Get the active execution
|
|
217
|
-
*
|
|
218
|
-
* @param {string} jobId
|
|
219
|
-
* @param {boolean} [allowZeroResults]
|
|
220
|
-
* @returns {Promise<import('@terascope/job-components').ExecutionConfig>}
|
|
221
|
-
*/
|
|
222
|
-
async function _getActiveExecutionId(jobId) {
|
|
223
|
-
return _getActiveExecution(jobId).then((ex) => ex.ex_id);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
async function getLatestExecutionId(jobId) {
|
|
227
|
-
return getLatestExecution(jobId).then((ex) => ex.ex_id);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
async function shutdown() {
|
|
231
|
-
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
async function addWorkers(jobId, workerCount) {
|
|
235
|
-
const exId = await _getActiveExecutionId(jobId);
|
|
236
|
-
return executionService.addWorkers(exId, workerCount);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
async function removeWorkers(jobId, workerCount) {
|
|
240
|
-
const exId = await _getActiveExecutionId(jobId);
|
|
241
|
-
return executionService.removeWorkers(exId, workerCount);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
async function setWorkers(jobId, workerCount) {
|
|
245
|
-
const exId = await _getActiveExecutionId(jobId);
|
|
246
|
-
return executionService.setWorkers(exId, workerCount);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
async function _ensureAssets(jobConfig) {
|
|
250
|
-
const jobAssets = uniq(jobConfig.assets || []);
|
|
251
|
-
if (isEmpty(jobAssets)) {
|
|
252
|
-
return cloneDeep(jobConfig);
|
|
253
|
-
}
|
|
254
|
-
// convert asset references to their id's
|
|
255
|
-
const assetIds = await spawnAssetsLoader(jobAssets);
|
|
256
|
-
if (!assetIds.length) {
|
|
257
|
-
throw new Error(`no asset id's were found for assets: ${JSON.stringify(jobAssets)}`);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
if (jobAssets.length !== assetIds.length) {
|
|
261
|
-
throw new Error(`job specified ${jobAssets.length} assets: ${jobAssets.assets} but only ${assetIds.length} where found, assets: ${assetIds}`);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// need to normalize asset identifiers to their id form
|
|
265
|
-
// but not mutate original job_spec
|
|
266
|
-
const parsedAssetJob = cloneDeep(jobConfig);
|
|
267
|
-
parsedAssetJob.assets = assetIds;
|
|
268
|
-
return parsedAssetJob;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
async function initialize() {
|
|
272
|
-
logger.info('job service is initializing...');
|
|
273
|
-
|
|
274
|
-
exStore = context.stores.execution;
|
|
275
|
-
jobStore = context.stores.jobs;
|
|
276
|
-
|
|
277
|
-
if (jobStore == null || exStore == null) {
|
|
278
|
-
throw new Error('Missing required stores');
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
executionService = context.services.execution;
|
|
282
|
-
if (executionService == null) {
|
|
283
|
-
throw new Error('Missing required services');
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
return {
|
|
288
|
-
submitJob,
|
|
289
|
-
updateJob,
|
|
290
|
-
startJob,
|
|
291
|
-
pauseJob,
|
|
292
|
-
resumeJob,
|
|
293
|
-
recoverJob,
|
|
294
|
-
setActiveState,
|
|
295
|
-
addWorkers,
|
|
296
|
-
removeWorkers,
|
|
297
|
-
setWorkers,
|
|
298
|
-
getLatestExecutionId,
|
|
299
|
-
getLatestExecution,
|
|
300
|
-
initialize,
|
|
301
|
-
shutdown,
|
|
302
|
-
}; // Load the initial pendingJobs state.
|
|
303
|
-
};
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
function hasKafkaConnector() {
|
|
4
|
-
try {
|
|
5
|
-
// eslint-disable-next-line
|
|
6
|
-
require('terafoundation_kafka_connector');
|
|
7
|
-
return true;
|
|
8
|
-
} catch (err) {
|
|
9
|
-
return false;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function getConnectors() {
|
|
14
|
-
const connectors = {
|
|
15
|
-
elasticsearch: {
|
|
16
|
-
default: {
|
|
17
|
-
host: ['localhost:9200']
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
'elasticsearch-next': {
|
|
21
|
-
default: {
|
|
22
|
-
node: ['localhost:9200']
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
if (hasKafkaConnector()) {
|
|
28
|
-
connectors.kafka = {
|
|
29
|
-
default: {
|
|
30
|
-
brokers: ['localhost:9092']
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return connectors;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
module.exports = {
|
|
39
|
-
terafoundation: {
|
|
40
|
-
environment: 'development',
|
|
41
|
-
connectors: getConnectors()
|
|
42
|
-
},
|
|
43
|
-
teraslice: {
|
|
44
|
-
master: true,
|
|
45
|
-
name: 'teracluster'
|
|
46
|
-
}
|
|
47
|
-
};
|
package/lib/config/index.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const { get } = require('@terascope/utils');
|
|
5
|
-
const { formats } = require('@terascope/job-components');
|
|
6
|
-
const { configSchema } = require('./schemas/system');
|
|
7
|
-
|
|
8
|
-
const terasliceOpPath = path.join(__dirname, '..');
|
|
9
|
-
|
|
10
|
-
function clusterName(configFile) {
|
|
11
|
-
return get(configFile, 'teraslice.name', null);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function getTerasliceConfig(sysconfig) {
|
|
15
|
-
return Object.assign({
|
|
16
|
-
name: 'teraslice',
|
|
17
|
-
default_config_file: path.join(__dirname, 'default-sysconfig.js'),
|
|
18
|
-
config_schema: configSchema,
|
|
19
|
-
schema_formats: formats,
|
|
20
|
-
cluster_name: clusterName,
|
|
21
|
-
shutdownMessaging: false,
|
|
22
|
-
start_workers: false,
|
|
23
|
-
}, sysconfig);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
module.exports = {
|
|
27
|
-
terasliceOpPath,
|
|
28
|
-
formats,
|
|
29
|
-
configSchema,
|
|
30
|
-
getTerasliceConfig,
|
|
31
|
-
clusterName,
|
|
32
|
-
};
|