teraslice 3.3.0 → 3.3.2
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/LICENSE +202 -0
- package/package.json +25 -28
- package/dist/src/interfaces.js +0 -12
- package/dist/src/lib/cluster/cluster_master.js +0 -246
- package/dist/src/lib/cluster/node_master.js +0 -355
- package/dist/src/lib/cluster/services/api.js +0 -663
- package/dist/src/lib/cluster/services/assets.js +0 -224
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/index.js +0 -192
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/interfaces.js +0 -2
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8s.js +0 -419
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8sDeploymentResource.js +0 -60
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8sJobResource.js +0 -55
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8sResource.js +0 -357
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8sServiceResource.js +0 -37
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8sState.js +0 -60
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/utils.js +0 -170
- package/dist/src/lib/cluster/services/cluster/backends/native/dispatch.js +0 -13
- package/dist/src/lib/cluster/services/cluster/backends/native/index.js +0 -526
- package/dist/src/lib/cluster/services/cluster/backends/native/messaging.js +0 -548
- package/dist/src/lib/cluster/services/cluster/backends/state-utils.js +0 -26
- package/dist/src/lib/cluster/services/cluster/index.js +0 -13
- package/dist/src/lib/cluster/services/execution.js +0 -435
- package/dist/src/lib/cluster/services/index.js +0 -6
- package/dist/src/lib/cluster/services/interfaces.js +0 -2
- package/dist/src/lib/cluster/services/jobs.js +0 -458
- package/dist/src/lib/config/default-sysconfig.js +0 -25
- package/dist/src/lib/config/index.js +0 -20
- package/dist/src/lib/config/schemas/system.js +0 -360
- package/dist/src/lib/storage/analytics.js +0 -86
- package/dist/src/lib/storage/assets.js +0 -401
- package/dist/src/lib/storage/backends/elasticsearch_store.js +0 -496
- package/dist/src/lib/storage/backends/mappings/analytics.js +0 -20
- package/dist/src/lib/storage/backends/mappings/asset.js +0 -32
- package/dist/src/lib/storage/backends/mappings/ex.js +0 -53
- package/dist/src/lib/storage/backends/mappings/job.js +0 -42
- package/dist/src/lib/storage/backends/mappings/state.js +0 -16
- package/dist/src/lib/storage/backends/s3_store.js +0 -237
- package/dist/src/lib/storage/execution.js +0 -302
- package/dist/src/lib/storage/index.js +0 -7
- package/dist/src/lib/storage/jobs.js +0 -81
- package/dist/src/lib/storage/state.js +0 -254
- package/dist/src/lib/utils/api_utils.js +0 -128
- package/dist/src/lib/utils/asset_utils.js +0 -94
- package/dist/src/lib/utils/date_utils.js +0 -52
- package/dist/src/lib/utils/encoding_utils.js +0 -27
- package/dist/src/lib/utils/events.js +0 -4
- package/dist/src/lib/utils/file_utils.js +0 -124
- package/dist/src/lib/utils/id_utils.js +0 -15
- package/dist/src/lib/utils/port_utils.js +0 -32
- package/dist/src/lib/workers/assets/index.js +0 -3
- package/dist/src/lib/workers/assets/loader-executable.js +0 -40
- package/dist/src/lib/workers/assets/loader.js +0 -73
- package/dist/src/lib/workers/assets/spawn.js +0 -55
- package/dist/src/lib/workers/context/execution-context.js +0 -12
- package/dist/src/lib/workers/context/terafoundation-context.js +0 -8
- package/dist/src/lib/workers/execution-controller/execution-analytics.js +0 -188
- package/dist/src/lib/workers/execution-controller/index.js +0 -1024
- package/dist/src/lib/workers/execution-controller/recovery.js +0 -151
- package/dist/src/lib/workers/execution-controller/scheduler.js +0 -390
- package/dist/src/lib/workers/execution-controller/slice-analytics.js +0 -96
- package/dist/src/lib/workers/helpers/job.js +0 -80
- package/dist/src/lib/workers/helpers/op-analytics.js +0 -22
- package/dist/src/lib/workers/helpers/terafoundation.js +0 -34
- package/dist/src/lib/workers/helpers/worker-shutdown.js +0 -147
- package/dist/src/lib/workers/metrics/index.js +0 -108
- package/dist/src/lib/workers/worker/index.js +0 -378
- package/dist/src/lib/workers/worker/slice.js +0 -122
- package/dist/test/config/schemas/system_schema-spec.js +0 -26
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/v2/k8s-v2-spec.js +0 -458
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/v2/k8sResource-v2-spec.js +0 -818
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/v2/k8sState-multicluster-v2-spec.js +0 -67
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/v2/k8sState-v2-spec.js +0 -84
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/v2/utils-v2-spec.js +0 -320
- package/dist/test/lib/cluster/services/cluster/backends/state-utils-spec.js +0 -37
- package/dist/test/node_master-spec.js +0 -194
- package/dist/test/services/api-spec.js +0 -79
- package/dist/test/services/assets-spec.js +0 -158
- package/dist/test/services/messaging-spec.js +0 -440
- package/dist/test/storage/assets_storage-spec.js +0 -95
- package/dist/test/storage/s3_store-spec.js +0 -149
- package/dist/test/test.config.js +0 -23
- package/dist/test/test.setup.js +0 -6
- package/dist/test/utils/api_utils-spec.js +0 -25
- package/dist/test/utils/asset_utils-spec.js +0 -141
- package/dist/test/utils/elastic_utils-spec.js +0 -25
- package/dist/test/workers/execution-controller/execution-controller-spec.js +0 -371
- package/dist/test/workers/execution-controller/execution-special-test-cases-spec.js +0 -519
- package/dist/test/workers/execution-controller/execution-test-cases-spec.js +0 -343
- package/dist/test/workers/execution-controller/recovery-spec.js +0 -160
- package/dist/test/workers/execution-controller/scheduler-spec.js +0 -249
- package/dist/test/workers/execution-controller/slice-analytics-spec.js +0 -121
- package/dist/test/workers/fixtures/ops/example-op/processor.js +0 -20
- package/dist/test/workers/fixtures/ops/example-op/schema.js +0 -19
- package/dist/test/workers/fixtures/ops/example-reader/fetcher.js +0 -20
- package/dist/test/workers/fixtures/ops/example-reader/schema.js +0 -41
- package/dist/test/workers/fixtures/ops/example-reader/slicer.js +0 -37
- package/dist/test/workers/fixtures/ops/new-op/processor.js +0 -29
- package/dist/test/workers/fixtures/ops/new-op/schema.js +0 -18
- package/dist/test/workers/fixtures/ops/new-reader/fetcher.js +0 -19
- package/dist/test/workers/fixtures/ops/new-reader/schema.js +0 -23
- package/dist/test/workers/fixtures/ops/new-reader/slicer.js +0 -13
- package/dist/test/workers/helpers/configs.js +0 -128
- package/dist/test/workers/helpers/execution-controller-helper.js +0 -49
- package/dist/test/workers/helpers/index.js +0 -5
- package/dist/test/workers/helpers/test-context.js +0 -210
- package/dist/test/workers/helpers/zip-directory.js +0 -25
- package/dist/test/workers/worker/slice-spec.js +0 -333
- package/dist/test/workers/worker/worker-spec.js +0 -356
|
@@ -1,343 +0,0 @@
|
|
|
1
|
-
import { pDelay, times, random, isNotNil } from '@terascope/core-utils';
|
|
2
|
-
import { ExecutionController as ExController } from '@terascope/teraslice-messaging';
|
|
3
|
-
import { TestContext } from '../helpers/index.js';
|
|
4
|
-
import { getTestCases } from '../helpers/execution-controller-helper.js';
|
|
5
|
-
import { findPort } from '../../../src/lib/utils/port_utils.js';
|
|
6
|
-
import { newId } from '../../../src/lib/utils/id_utils.js';
|
|
7
|
-
import { getPackageJSON } from '../../../src/lib/utils/file_utils.js';
|
|
8
|
-
import { ExecutionController } from '../../../src/lib/workers/execution-controller/index.js';
|
|
9
|
-
const ExecutionControllerClient = ExController.Client;
|
|
10
|
-
describe('ExecutionController Test Cases', () => {
|
|
11
|
-
// [ message, config ]
|
|
12
|
-
const testCases = [
|
|
13
|
-
[
|
|
14
|
-
'when processing one slice',
|
|
15
|
-
{
|
|
16
|
-
slicerResults: [{ example: 'single-slice' }, null],
|
|
17
|
-
body: { example: 'single-slice' },
|
|
18
|
-
count: 1,
|
|
19
|
-
analytics: false
|
|
20
|
-
}
|
|
21
|
-
],
|
|
22
|
-
[
|
|
23
|
-
'when processing a slicer requests a specific worker',
|
|
24
|
-
{
|
|
25
|
-
slicerResults: [
|
|
26
|
-
{ request_worker: 'specific-worker-1', example: 'specific-worker' },
|
|
27
|
-
null
|
|
28
|
-
],
|
|
29
|
-
workerIds: ['specific-worker-1'],
|
|
30
|
-
body: { request_worker: 'specific-worker-1', example: 'specific-worker' },
|
|
31
|
-
count: 1,
|
|
32
|
-
analytics: true
|
|
33
|
-
}
|
|
34
|
-
],
|
|
35
|
-
[
|
|
36
|
-
'when processing sub-slices',
|
|
37
|
-
{
|
|
38
|
-
slicerResults: [
|
|
39
|
-
[{ example: 'subslice' }, { example: 'subslice' }, { example: 'subslice' }],
|
|
40
|
-
null
|
|
41
|
-
],
|
|
42
|
-
emitSlicerRecursion: true,
|
|
43
|
-
count: 3,
|
|
44
|
-
body: { example: 'subslice' },
|
|
45
|
-
analytics: false
|
|
46
|
-
}
|
|
47
|
-
],
|
|
48
|
-
[
|
|
49
|
-
'when processing slices with multiple workers and one reconnects',
|
|
50
|
-
{
|
|
51
|
-
slicerResults: [
|
|
52
|
-
{ example: 'slice-disconnect' },
|
|
53
|
-
{ example: 'slice-disconnect' },
|
|
54
|
-
{ example: 'slice-disconnect' },
|
|
55
|
-
{ example: 'slice-disconnect' },
|
|
56
|
-
null
|
|
57
|
-
],
|
|
58
|
-
reconnect: true,
|
|
59
|
-
body: { example: 'slice-disconnect' },
|
|
60
|
-
count: 4,
|
|
61
|
-
analytics: false
|
|
62
|
-
}
|
|
63
|
-
],
|
|
64
|
-
[
|
|
65
|
-
'when processing a slice with dynamic queue length',
|
|
66
|
-
{
|
|
67
|
-
slicerResults: [
|
|
68
|
-
{ example: 'slice-dynamic' },
|
|
69
|
-
{ example: 'slice-dynamic' },
|
|
70
|
-
{ example: 'slice-dynamic' },
|
|
71
|
-
{ example: 'slice-dynamic' },
|
|
72
|
-
null
|
|
73
|
-
],
|
|
74
|
-
reconnect: true,
|
|
75
|
-
slicerQueueLength: 'QUEUE_MINIMUM_SIZE',
|
|
76
|
-
body: { example: 'slice-dynamic' },
|
|
77
|
-
count: 4,
|
|
78
|
-
workers: 2,
|
|
79
|
-
analytics: true
|
|
80
|
-
}
|
|
81
|
-
],
|
|
82
|
-
[
|
|
83
|
-
'when processing a slice and the slicer throws an error',
|
|
84
|
-
{
|
|
85
|
-
slicerResults: [{ example: 'slice-failure' }, { error: 'Slice failure' }, null],
|
|
86
|
-
slicerFails: true,
|
|
87
|
-
body: { example: 'slice-failure' },
|
|
88
|
-
count: 1,
|
|
89
|
-
analytics: false
|
|
90
|
-
}
|
|
91
|
-
],
|
|
92
|
-
[
|
|
93
|
-
'when processing a slice fails',
|
|
94
|
-
{
|
|
95
|
-
slicerResults: [{ example: 'slice-fail' }, null],
|
|
96
|
-
sliceFails: true,
|
|
97
|
-
body: { example: 'slice-fail' },
|
|
98
|
-
count: 1,
|
|
99
|
-
analytics: false
|
|
100
|
-
}
|
|
101
|
-
],
|
|
102
|
-
[
|
|
103
|
-
'when processing a slicer that emits slicer events',
|
|
104
|
-
{
|
|
105
|
-
slicerResults: [{ example: 'slicer-slice-range-expansion' }, null],
|
|
106
|
-
updateMetadata: true,
|
|
107
|
-
emitSlicerRangeExpansion: true,
|
|
108
|
-
body: { example: 'slicer-slice-range-expansion' },
|
|
109
|
-
count: 1,
|
|
110
|
-
analytics: true
|
|
111
|
-
}
|
|
112
|
-
],
|
|
113
|
-
[
|
|
114
|
-
'when processing a slice and the execution is paused and resumed',
|
|
115
|
-
{
|
|
116
|
-
slicerResults: [{ example: 'slice-pause-and-resume' }, null],
|
|
117
|
-
pauseAndResume: true,
|
|
118
|
-
body: { example: 'slice-pause-and-resume' },
|
|
119
|
-
count: 1,
|
|
120
|
-
analytics: false
|
|
121
|
-
}
|
|
122
|
-
]
|
|
123
|
-
];
|
|
124
|
-
// for testing add a "only" property to the test cases you want
|
|
125
|
-
// or add a skip property to the test cases you don't want
|
|
126
|
-
describe.each(getTestCases(testCases))('%s', (m, options) => {
|
|
127
|
-
const { slicerResults, slicerQueueLength, count, lifecycle = 'once', body, reconnect = false, analytics = false, workers = 1, pauseAndResume = false, sliceFails = false, slicerFails = false, updateMetadata, emitSlicerRecursion = false, emitSlicerRangeExpansion = false, workerIds = [] } = options;
|
|
128
|
-
let exController;
|
|
129
|
-
let testContext;
|
|
130
|
-
let slices;
|
|
131
|
-
let exStore;
|
|
132
|
-
let stateStore;
|
|
133
|
-
let executionRecord;
|
|
134
|
-
beforeAll(async () => {
|
|
135
|
-
slices = [];
|
|
136
|
-
const port = await findPort();
|
|
137
|
-
testContext = new TestContext({
|
|
138
|
-
assignment: 'execution_controller',
|
|
139
|
-
slicerPort: port,
|
|
140
|
-
slicerQueueLength,
|
|
141
|
-
slicerResults,
|
|
142
|
-
timeout: reconnect ? 5000 : 3000,
|
|
143
|
-
lifecycle,
|
|
144
|
-
workers,
|
|
145
|
-
analytics,
|
|
146
|
-
updateMetadata
|
|
147
|
-
});
|
|
148
|
-
// needs to be in this order
|
|
149
|
-
await testContext.initialize(true);
|
|
150
|
-
await testContext.addClusterMaster();
|
|
151
|
-
const { clusterMaster, exId } = testContext;
|
|
152
|
-
stateStore = await testContext.addStateStore();
|
|
153
|
-
exStore = await testContext.addExStore();
|
|
154
|
-
exController = new ExecutionController(testContext.context, testContext.executionContext);
|
|
155
|
-
const { network_latency_buffer: networkLatencyBuffer, action_timeout: actionTimeout } = testContext.context.sysconfig.teraslice;
|
|
156
|
-
testContext.attachCleanup(() => exController.shutdown());
|
|
157
|
-
const opCount = testContext.executionContext.config.operations.length;
|
|
158
|
-
await exController.initialize();
|
|
159
|
-
const socketOptions = reconnect
|
|
160
|
-
? {
|
|
161
|
-
reconnection: true,
|
|
162
|
-
reconnectionAttempts: 10,
|
|
163
|
-
reconnectionDelay: 500,
|
|
164
|
-
reconnectionDelayMax: 500
|
|
165
|
-
}
|
|
166
|
-
: {
|
|
167
|
-
reconnection: false
|
|
168
|
-
};
|
|
169
|
-
let firedReconnect = false;
|
|
170
|
-
const workerClients = [];
|
|
171
|
-
clusterMaster.onExecutionFinished(() => {
|
|
172
|
-
workerClients.forEach((workerClient) => {
|
|
173
|
-
workerClient.shutdown();
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
async function startWorker(n) {
|
|
177
|
-
const workerId = (workerIds.length && isNotNil(n)) ? workerIds[n] : newId('worker');
|
|
178
|
-
const workerClient = new ExecutionControllerClient({
|
|
179
|
-
executionControllerUrl: `http://localhost:${port}`,
|
|
180
|
-
workerId,
|
|
181
|
-
networkLatencyBuffer,
|
|
182
|
-
workerDisconnectTimeout: 1000,
|
|
183
|
-
actionTimeout,
|
|
184
|
-
connectTimeout: 1000,
|
|
185
|
-
socketOptions
|
|
186
|
-
});
|
|
187
|
-
workerClients.push(workerClient);
|
|
188
|
-
testContext.attachCleanup(() => workerClient.shutdown());
|
|
189
|
-
await workerClient.start();
|
|
190
|
-
async function waitForReconnect() {
|
|
191
|
-
if (!reconnect)
|
|
192
|
-
return;
|
|
193
|
-
if (firedReconnect)
|
|
194
|
-
return;
|
|
195
|
-
firedReconnect = true;
|
|
196
|
-
await Promise.all([
|
|
197
|
-
workerClient.forceReconnect(),
|
|
198
|
-
exController.server.waitForClientReady(workerId)
|
|
199
|
-
]);
|
|
200
|
-
}
|
|
201
|
-
const isDone = () => exController.isExecutionDone;
|
|
202
|
-
async function processWork() {
|
|
203
|
-
if (isDone())
|
|
204
|
-
return;
|
|
205
|
-
const slice = await workerClient.waitForSlice(isDone);
|
|
206
|
-
if (!slice)
|
|
207
|
-
return;
|
|
208
|
-
slices.push(slice);
|
|
209
|
-
const msg = { slice };
|
|
210
|
-
if (analytics) {
|
|
211
|
-
msg.analytics = {
|
|
212
|
-
time: times(opCount, () => random(0, 2000)),
|
|
213
|
-
size: times(opCount, () => random(0, 100)),
|
|
214
|
-
memory: times(opCount, () => random(0, 10000))
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
// add a natural delay for completing a slice
|
|
218
|
-
await pDelay(100);
|
|
219
|
-
if (sliceFails) {
|
|
220
|
-
msg.error = 'Oh no, slice failure';
|
|
221
|
-
await stateStore.updateState(slice, 'error', msg.error);
|
|
222
|
-
}
|
|
223
|
-
else {
|
|
224
|
-
await stateStore.updateState(slice, 'completed');
|
|
225
|
-
}
|
|
226
|
-
async function completeSlice() {
|
|
227
|
-
if (pauseAndResume) {
|
|
228
|
-
await Promise.all([
|
|
229
|
-
clusterMaster
|
|
230
|
-
.sendExecutionPause(exId)
|
|
231
|
-
.then(() => clusterMaster.sendExecutionResume(exId)),
|
|
232
|
-
workerClient.sendSliceComplete(msg)
|
|
233
|
-
]);
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
await pDelay(0);
|
|
237
|
-
await workerClient.sendSliceComplete(msg);
|
|
238
|
-
}
|
|
239
|
-
await Promise.all([waitForReconnect(), completeSlice()]);
|
|
240
|
-
await processWork();
|
|
241
|
-
}
|
|
242
|
-
await processWork();
|
|
243
|
-
}
|
|
244
|
-
function startWorkers() {
|
|
245
|
-
return Promise.all(times(workers, startWorker));
|
|
246
|
-
}
|
|
247
|
-
clusterMaster.onClientAvailable(() => {
|
|
248
|
-
if (emitSlicerRecursion) {
|
|
249
|
-
exController.events.emit('slicer:slice:recursion');
|
|
250
|
-
}
|
|
251
|
-
if (emitSlicerRangeExpansion) {
|
|
252
|
-
exController.events.emit('slicer:slice:range_expansion');
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
const requestAnayltics = setTimeout(async () => {
|
|
256
|
-
try {
|
|
257
|
-
await clusterMaster.sendExecutionAnalyticsRequest(exId);
|
|
258
|
-
}
|
|
259
|
-
catch (err) {
|
|
260
|
-
// it shouldn't matter
|
|
261
|
-
}
|
|
262
|
-
}, 100);
|
|
263
|
-
testContext.attachCleanup(() => clearTimeout(requestAnayltics));
|
|
264
|
-
await Promise.all([startWorkers(), exController.run()]);
|
|
265
|
-
clearTimeout(requestAnayltics);
|
|
266
|
-
executionRecord = await exStore.get(exId);
|
|
267
|
-
});
|
|
268
|
-
afterAll(() => testContext.cleanup());
|
|
269
|
-
it('should process the correct slices', async () => {
|
|
270
|
-
expect(slices).toBeArrayOfSize(count);
|
|
271
|
-
times(count, (i) => {
|
|
272
|
-
const slice = slices[i];
|
|
273
|
-
expect(slice).toHaveProperty('request');
|
|
274
|
-
expect(slice.request).toEqual(body);
|
|
275
|
-
});
|
|
276
|
-
});
|
|
277
|
-
it('should have the correct number of slices', async () => {
|
|
278
|
-
const { exId } = testContext.executionContext;
|
|
279
|
-
const errorCount = await stateStore.count(`ex_id:${exId} AND state:error`, 0);
|
|
280
|
-
const completedCount = await stateStore.count(`ex_id:${exId}`, 0);
|
|
281
|
-
if (sliceFails) {
|
|
282
|
-
expect(errorCount).toEqual(count);
|
|
283
|
-
}
|
|
284
|
-
else {
|
|
285
|
-
expect(completedCount).toEqual(count);
|
|
286
|
-
expect(errorCount).toEqual(0);
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
|
-
it('should have the correct execution status', () => {
|
|
290
|
-
const { exId } = testContext.executionContext;
|
|
291
|
-
expect(executionRecord).toBeObject();
|
|
292
|
-
expect(executionRecord).toHaveProperty('_slicer_stats.processed');
|
|
293
|
-
expect(executionRecord).toHaveProperty('_slicer_stats.queued');
|
|
294
|
-
expect(executionRecord).toHaveProperty('_slicer_stats.slicers');
|
|
295
|
-
if (sliceFails || slicerFails) {
|
|
296
|
-
if (sliceFails) {
|
|
297
|
-
expect(executionRecord).toHaveProperty('_failureReason', `execution: ${exId} had 1 slice failure during processing`);
|
|
298
|
-
expect(executionRecord._slicer_stats.failed).toEqual(count);
|
|
299
|
-
expect(executionRecord).toMatchObject({
|
|
300
|
-
_has_errors: true,
|
|
301
|
-
_status: 'failed'
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
if (slicerFails) {
|
|
305
|
-
expect(executionRecord._failureReason).toStartWith(`TSError: slicer for ex ${exId} had an error, shutting down execution, caused by Error: Slice failure`);
|
|
306
|
-
expect(executionRecord._slicer_stats.failed).toEqual(0);
|
|
307
|
-
expect(executionRecord).toMatchObject({
|
|
308
|
-
_has_errors: true,
|
|
309
|
-
_status: 'failed'
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
else {
|
|
314
|
-
expect(executionRecord).toMatchObject({
|
|
315
|
-
_has_errors: false,
|
|
316
|
-
_status: 'completed'
|
|
317
|
-
});
|
|
318
|
-
if (slicerQueueLength !== 'QUEUE_MINIMUM_SIZE') {
|
|
319
|
-
expect(executionRecord._slicer_stats.processed).toEqual(count);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
expect(executionRecord._slicer_stats.workers_joined).toBeGreaterThanOrEqual(1);
|
|
323
|
-
if (reconnect && slicerQueueLength !== 'QUEUE_MINIMUM_SIZE') {
|
|
324
|
-
expect(executionRecord._slicer_stats.workers_reconnected).toBeGreaterThan(0);
|
|
325
|
-
}
|
|
326
|
-
if (emitSlicerRangeExpansion) {
|
|
327
|
-
expect(executionRecord._slicer_stats).toHaveProperty('slice_range_expansion', 1);
|
|
328
|
-
}
|
|
329
|
-
if (emitSlicerRecursion) {
|
|
330
|
-
expect(executionRecord._slicer_stats).toHaveProperty('subslices', 1);
|
|
331
|
-
}
|
|
332
|
-
});
|
|
333
|
-
it('should update the execution metadata (from the context apis)', () => {
|
|
334
|
-
const metadata = updateMetadata ? { slice_calls: count + 1 } : {};
|
|
335
|
-
expect(executionRecord).toHaveProperty('metadata', metadata);
|
|
336
|
-
});
|
|
337
|
-
it('should have the correct teraslice version', () => {
|
|
338
|
-
const terasliceVersion = `v${getPackageJSON().version}`;
|
|
339
|
-
expect(executionRecord.teraslice_version).toBe(terasliceVersion);
|
|
340
|
-
});
|
|
341
|
-
});
|
|
342
|
-
});
|
|
343
|
-
//# sourceMappingURL=execution-test-cases-spec.js.map
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import { pDelay, pWhile, debugLogger } from '@terascope/core-utils';
|
|
2
|
-
import { EventEmitter } from 'node:events';
|
|
3
|
-
import { RecoveryModule } from '../../../src/lib/workers/execution-controller/recovery.js';
|
|
4
|
-
const eventEmitter = new EventEmitter();
|
|
5
|
-
const eventEmitter2 = new EventEmitter();
|
|
6
|
-
describe('execution recoveryModule', () => {
|
|
7
|
-
const logger = debugLogger('execution-recoveryModule');
|
|
8
|
-
let testSlices = [{ slice_id: 1 }, { slice_id: 2 }];
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
testSlices = [{ slice_id: 1 }, { slice_id: 2 }];
|
|
11
|
-
});
|
|
12
|
-
const context = {
|
|
13
|
-
apis: {
|
|
14
|
-
foundation: {
|
|
15
|
-
makeLogger: () => logger,
|
|
16
|
-
getSystemEvents: () => eventEmitter
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
sysconfig: {
|
|
20
|
-
teraslice: {
|
|
21
|
-
shutdown_timeout: 1
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
const stateStore = {
|
|
26
|
-
recoverSlices: () => {
|
|
27
|
-
const data = testSlices.slice();
|
|
28
|
-
testSlices = [];
|
|
29
|
-
return Promise.resolve(data);
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
const executionContext = {
|
|
33
|
-
config: {
|
|
34
|
-
slicers: 2,
|
|
35
|
-
recovered_execution: '9999'
|
|
36
|
-
},
|
|
37
|
-
ex_id: '1234',
|
|
38
|
-
job_id: '5678'
|
|
39
|
-
};
|
|
40
|
-
function waitFor(fn, time) {
|
|
41
|
-
return new Promise((resolve) => {
|
|
42
|
-
setTimeout(() => {
|
|
43
|
-
fn();
|
|
44
|
-
resolve(true);
|
|
45
|
-
}, time);
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
function sendEvent(event, data, emitter) {
|
|
49
|
-
const events = emitter || eventEmitter;
|
|
50
|
-
return () => {
|
|
51
|
-
events.emit(event, data);
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
async function getRecoveryModule() {
|
|
55
|
-
const module = new RecoveryModule(context, executionContext);
|
|
56
|
-
await module.initialize(stateStore);
|
|
57
|
-
return module;
|
|
58
|
-
}
|
|
59
|
-
it('has the proper methods', async () => {
|
|
60
|
-
const recoveryModule = await getRecoveryModule();
|
|
61
|
-
expect(recoveryModule.initialize).toBeFunction();
|
|
62
|
-
expect(recoveryModule.handle).toBeFunction();
|
|
63
|
-
expect(recoveryModule.getSlice).toBeFunction();
|
|
64
|
-
expect(recoveryModule.getSlices).toBeFunction();
|
|
65
|
-
expect(recoveryModule.recoveryComplete).toBeFunction();
|
|
66
|
-
expect(recoveryModule.shutdown).toBeFunction();
|
|
67
|
-
});
|
|
68
|
-
it('manages retry slice state', async () => {
|
|
69
|
-
const recoveryModule = await getRecoveryModule();
|
|
70
|
-
// @ts-expect-error
|
|
71
|
-
expect(recoveryModule._retryState()).toEqual({});
|
|
72
|
-
// @ts-expect-error
|
|
73
|
-
recoveryModule._setId({ slice_id: 1 });
|
|
74
|
-
// @ts-expect-error
|
|
75
|
-
expect(recoveryModule._retryState()).toEqual({ 1: true });
|
|
76
|
-
// @ts-expect-error
|
|
77
|
-
expect(recoveryModule._recoveryBatchCompleted()).toEqual(false);
|
|
78
|
-
// @ts-expect-error
|
|
79
|
-
recoveryModule._sliceComplete({ slice: { slice_id: 1 } });
|
|
80
|
-
// @ts-expect-error
|
|
81
|
-
expect(recoveryModule._retryState()).toEqual({ 1: false });
|
|
82
|
-
// @ts-expect-error
|
|
83
|
-
expect(recoveryModule._recoveryBatchCompleted()).toEqual(true);
|
|
84
|
-
});
|
|
85
|
-
it('initializes and sets up listeners', async () => {
|
|
86
|
-
const recoveryModule = await getRecoveryModule();
|
|
87
|
-
// @ts-expect-error
|
|
88
|
-
expect(recoveryModule._retryState()).toEqual({});
|
|
89
|
-
// @ts-expect-error
|
|
90
|
-
expect(recoveryModule._recoveryBatchCompleted()).toEqual(true);
|
|
91
|
-
// @ts-expect-error
|
|
92
|
-
recoveryModule._setId({ slice_id: 1 });
|
|
93
|
-
// @ts-expect-error
|
|
94
|
-
recoveryModule._setId({ slice_id: 2 });
|
|
95
|
-
const sendSucess = sendEvent('slice:success', { slice: { slice_id: 1 } });
|
|
96
|
-
const sendSucess2 = sendEvent('slice:success', { slice: { slice_id: 2 } });
|
|
97
|
-
return Promise.all([
|
|
98
|
-
// @ts-expect-error
|
|
99
|
-
recoveryModule._waitForRecoveryBatchCompletion(),
|
|
100
|
-
waitFor(sendSucess, 100),
|
|
101
|
-
waitFor(sendSucess2, 250)
|
|
102
|
-
]).then(() => {
|
|
103
|
-
// @ts-expect-error
|
|
104
|
-
expect(recoveryModule._retryState()).toEqual({
|
|
105
|
-
1: false,
|
|
106
|
-
2: false
|
|
107
|
-
});
|
|
108
|
-
// @ts-expect-error
|
|
109
|
-
expect(recoveryModule._recoveryBatchCompleted()).toEqual(true);
|
|
110
|
-
// @ts-expect-error
|
|
111
|
-
return recoveryModule._setId({ slice_id: 2 });
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
it('can recover slices', async () => {
|
|
115
|
-
context.apis.foundation.getSystemEvents = () => eventEmitter2;
|
|
116
|
-
const recoveryModule = await getRecoveryModule();
|
|
117
|
-
const data1 = { slice_id: 1 };
|
|
118
|
-
const data2 = { slice_id: 2 };
|
|
119
|
-
const sendSucess1 = sendEvent('slice:success', { slice: data1 }, eventEmitter2);
|
|
120
|
-
const sendSucess2 = sendEvent('slice:success', { slice: data2 }, eventEmitter2);
|
|
121
|
-
let allDoneEventFired = false;
|
|
122
|
-
eventEmitter2.on('execution:recovery:complete', () => {
|
|
123
|
-
allDoneEventFired = true;
|
|
124
|
-
});
|
|
125
|
-
expect(recoveryModule.recoveryComplete()).toEqual(false);
|
|
126
|
-
const createSlicesPromise = pWhile(() => recoveryModule.handle(), { timeoutMs: 5000 });
|
|
127
|
-
const slicer = async () => {
|
|
128
|
-
await pWhile(async () => {
|
|
129
|
-
if (recoveryModule.sliceCount() || recoveryModule.recoveryComplete())
|
|
130
|
-
return true;
|
|
131
|
-
await pDelay(10);
|
|
132
|
-
return false;
|
|
133
|
-
}, { timeoutMs: 5000 });
|
|
134
|
-
return recoveryModule.getSlice();
|
|
135
|
-
};
|
|
136
|
-
return Promise.all([waitFor(sendSucess1, 100)])
|
|
137
|
-
.then(() => {
|
|
138
|
-
expect(recoveryModule.recoveryComplete()).toEqual(false);
|
|
139
|
-
return slicer();
|
|
140
|
-
})
|
|
141
|
-
.then((slice) => {
|
|
142
|
-
expect(slice).toEqual({ slice_id: 1 });
|
|
143
|
-
expect(recoveryModule.recoveryComplete()).toEqual(false);
|
|
144
|
-
return waitFor(sendSucess2, 124);
|
|
145
|
-
})
|
|
146
|
-
.then(() => slicer())
|
|
147
|
-
.then((slice) => {
|
|
148
|
-
expect(slice).toEqual({ slice_id: 2 });
|
|
149
|
-
expect(recoveryModule.recoveryComplete()).toEqual(false);
|
|
150
|
-
return Promise.all([slicer(), waitFor(() => { }, 150)]);
|
|
151
|
-
})
|
|
152
|
-
.then(([slice]) => {
|
|
153
|
-
expect(slice).toBeUndefined();
|
|
154
|
-
expect(allDoneEventFired).toEqual(true);
|
|
155
|
-
expect(recoveryModule.recoveryComplete()).toEqual(true);
|
|
156
|
-
return createSlicesPromise;
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
//# sourceMappingURL=recovery-spec.js.map
|