teraslice 2.10.0 → 2.12.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/dist/src/interfaces.js +12 -0
- package/dist/src/lib/cluster/cluster_master.js +246 -0
- package/dist/src/lib/cluster/node_master.js +355 -0
- package/dist/src/lib/cluster/services/api.js +663 -0
- package/dist/src/lib/cluster/services/assets.js +226 -0
- package/dist/src/lib/cluster/services/cluster/backends/kubernetes/index.js +192 -0
- package/dist/src/lib/cluster/services/cluster/backends/kubernetes/k8s.js +481 -0
- package/dist/src/lib/cluster/services/cluster/backends/kubernetes/k8sResource.js +414 -0
- package/dist/src/lib/cluster/services/cluster/backends/kubernetes/k8sState.js +59 -0
- package/dist/src/lib/cluster/services/cluster/backends/kubernetes/utils.js +43 -0
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/index.js +192 -0
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/interfaces.js +2 -0
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8s.js +423 -0
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8sDeploymentResource.js +60 -0
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8sJobResource.js +55 -0
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8sResource.js +359 -0
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8sServiceResource.js +37 -0
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/k8sState.js +60 -0
- package/dist/src/lib/cluster/services/cluster/backends/kubernetesV2/utils.js +170 -0
- package/dist/src/lib/cluster/services/cluster/backends/native/dispatch.js +13 -0
- package/dist/src/lib/cluster/services/cluster/backends/native/index.js +526 -0
- package/dist/src/lib/cluster/services/cluster/backends/native/messaging.js +547 -0
- package/dist/src/lib/cluster/services/cluster/backends/state-utils.js +26 -0
- package/dist/src/lib/cluster/services/cluster/index.js +17 -0
- package/dist/src/lib/cluster/services/execution.js +435 -0
- package/dist/src/lib/cluster/services/index.js +6 -0
- package/dist/src/lib/cluster/services/interfaces.js +2 -0
- package/dist/src/lib/cluster/services/jobs.js +454 -0
- package/dist/src/lib/config/default-sysconfig.js +26 -0
- package/dist/src/lib/config/index.js +22 -0
- package/dist/src/lib/config/schemas/system.js +360 -0
- package/dist/src/lib/storage/analytics.js +86 -0
- package/dist/src/lib/storage/assets.js +401 -0
- package/dist/src/lib/storage/backends/elasticsearch_store.js +494 -0
- package/dist/src/lib/storage/backends/mappings/analytics.js +50 -0
- package/dist/src/lib/storage/backends/mappings/asset.js +41 -0
- package/dist/src/lib/storage/backends/mappings/ex.js +62 -0
- package/dist/src/lib/storage/backends/mappings/job.js +38 -0
- package/dist/src/lib/storage/backends/mappings/state.js +38 -0
- package/dist/src/lib/storage/backends/s3_store.js +237 -0
- package/dist/src/lib/storage/execution.js +300 -0
- package/dist/src/lib/storage/index.js +7 -0
- package/dist/src/lib/storage/jobs.js +81 -0
- package/dist/src/lib/storage/state.js +255 -0
- package/dist/src/lib/utils/api_utils.js +157 -0
- package/dist/src/lib/utils/asset_utils.js +94 -0
- package/dist/src/lib/utils/date_utils.js +52 -0
- package/dist/src/lib/utils/encoding_utils.js +27 -0
- package/dist/src/lib/utils/events.js +4 -0
- package/dist/src/lib/utils/file_utils.js +124 -0
- package/dist/src/lib/utils/id_utils.js +15 -0
- package/dist/src/lib/utils/port_utils.js +32 -0
- package/dist/src/lib/workers/assets/index.js +3 -0
- package/dist/src/lib/workers/assets/loader-executable.js +40 -0
- package/dist/src/lib/workers/assets/loader.js +73 -0
- package/dist/src/lib/workers/assets/spawn.js +55 -0
- package/dist/src/lib/workers/context/execution-context.js +12 -0
- package/dist/src/lib/workers/context/terafoundation-context.js +8 -0
- package/dist/src/lib/workers/execution-controller/execution-analytics.js +188 -0
- package/dist/src/lib/workers/execution-controller/index.js +1024 -0
- package/dist/src/lib/workers/execution-controller/recovery.js +151 -0
- package/dist/src/lib/workers/execution-controller/scheduler.js +390 -0
- package/dist/src/lib/workers/execution-controller/slice-analytics.js +96 -0
- package/dist/src/lib/workers/helpers/job.js +80 -0
- package/dist/src/lib/workers/helpers/op-analytics.js +22 -0
- package/dist/src/lib/workers/helpers/terafoundation.js +34 -0
- package/dist/src/lib/workers/helpers/worker-shutdown.js +169 -0
- package/dist/src/lib/workers/metrics/index.js +108 -0
- package/dist/src/lib/workers/worker/index.js +378 -0
- package/dist/src/lib/workers/worker/slice.js +122 -0
- package/dist/test/config/schemas/system_schema-spec.js +37 -0
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/k8s-spec.js +316 -0
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/k8sResource-spec.js +795 -0
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/k8sState-multicluster-spec.js +67 -0
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/k8sState-spec.js +84 -0
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/utils-spec.js +132 -0
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/v2/k8s-v2-spec.js +455 -0
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/v2/k8sResource-v2-spec.js +818 -0
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/v2/k8sState-multicluster-v2-spec.js +67 -0
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/v2/k8sState-v2-spec.js +84 -0
- package/dist/test/lib/cluster/services/cluster/backends/kubernetes/v2/utils-v2-spec.js +320 -0
- package/dist/test/lib/cluster/services/cluster/backends/state-utils-spec.js +37 -0
- package/dist/test/node_master-spec.js +188 -0
- package/dist/test/services/api-spec.js +80 -0
- package/dist/test/services/assets-spec.js +158 -0
- package/dist/test/services/messaging-spec.js +440 -0
- package/dist/test/storage/assets_storage-spec.js +95 -0
- package/dist/test/storage/s3_store-spec.js +138 -0
- package/dist/test/test.config.js +8 -0
- package/dist/test/test.setup.js +6 -0
- package/dist/test/utils/api_utils-spec.js +86 -0
- package/dist/test/utils/asset_utils-spec.js +141 -0
- package/dist/test/utils/elastic_utils-spec.js +25 -0
- package/dist/test/workers/execution-controller/execution-controller-spec.js +371 -0
- package/dist/test/workers/execution-controller/execution-special-test-cases-spec.js +520 -0
- package/dist/test/workers/execution-controller/execution-test-cases-spec.js +338 -0
- package/dist/test/workers/execution-controller/recovery-spec.js +160 -0
- package/dist/test/workers/execution-controller/scheduler-spec.js +249 -0
- package/dist/test/workers/execution-controller/slice-analytics-spec.js +121 -0
- package/dist/test/workers/fixtures/ops/example-op/processor.js +20 -0
- package/dist/test/workers/fixtures/ops/example-op/schema.js +19 -0
- package/dist/test/workers/fixtures/ops/example-reader/fetcher.js +20 -0
- package/dist/test/workers/fixtures/ops/example-reader/schema.js +41 -0
- package/dist/test/workers/fixtures/ops/example-reader/slicer.js +37 -0
- package/dist/test/workers/fixtures/ops/new-op/processor.js +29 -0
- package/dist/test/workers/fixtures/ops/new-op/schema.js +18 -0
- package/dist/test/workers/fixtures/ops/new-reader/fetcher.js +19 -0
- package/dist/test/workers/fixtures/ops/new-reader/schema.js +23 -0
- package/dist/test/workers/fixtures/ops/new-reader/slicer.js +13 -0
- package/dist/test/workers/helpers/configs.js +130 -0
- package/dist/test/workers/helpers/execution-controller-helper.js +49 -0
- package/dist/test/workers/helpers/index.js +5 -0
- package/dist/test/workers/helpers/test-context.js +210 -0
- package/dist/test/workers/helpers/zip-directory.js +25 -0
- package/dist/test/workers/worker/slice-spec.js +333 -0
- package/dist/test/workers/worker/worker-spec.js +356 -0
- package/package.json +94 -93
- package/service.js +0 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { makeISODate } from '@terascope/utils';
|
|
2
|
+
import { JobValidator } from '@terascope/job-components';
|
|
3
|
+
import { JobsStorage, ExecutionStorage, StateStorage } from '../../storage/index.js';
|
|
4
|
+
// TODO: fix type here
|
|
5
|
+
export async function validateJob(context, jobSpec) {
|
|
6
|
+
const jobValidator = new JobValidator(context);
|
|
7
|
+
try {
|
|
8
|
+
return await jobValidator.validateConfig(jobSpec);
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
throw new Error(`validating job: ${error}`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export async function initializeTestExecution({ context, config, stores = {}, isRecovery = false, cleanupType, createRecovery = true, shutdownStores = false, recoverySlices = [], lastStatus = 'failed' }) {
|
|
15
|
+
if (!stores.jobStore) {
|
|
16
|
+
const [jobStore, exStore, stateStore] = await Promise.all([
|
|
17
|
+
(async () => {
|
|
18
|
+
const store = new JobsStorage(context);
|
|
19
|
+
await store.initialize();
|
|
20
|
+
return store;
|
|
21
|
+
})(),
|
|
22
|
+
(async () => {
|
|
23
|
+
const store = new ExecutionStorage(context);
|
|
24
|
+
await store.initialize();
|
|
25
|
+
return store;
|
|
26
|
+
})(),
|
|
27
|
+
(async () => {
|
|
28
|
+
const store = new StateStorage(context);
|
|
29
|
+
await store.initialize();
|
|
30
|
+
return store;
|
|
31
|
+
})(),
|
|
32
|
+
]);
|
|
33
|
+
stores.jobStore = jobStore;
|
|
34
|
+
stores.exStore = exStore;
|
|
35
|
+
stores.stateStore = stateStore;
|
|
36
|
+
}
|
|
37
|
+
const validJob = await validateJob(context, config);
|
|
38
|
+
const jobSpec = await stores.jobStore.create(config);
|
|
39
|
+
const job = Object.assign({}, jobSpec, validJob, {
|
|
40
|
+
job_id: jobSpec.job_id
|
|
41
|
+
});
|
|
42
|
+
// @ts-expect-error
|
|
43
|
+
const slicerHostname = job.slicer_hostname;
|
|
44
|
+
// @ts-expect-error
|
|
45
|
+
const slicerPort = job.slicer_port;
|
|
46
|
+
let ex;
|
|
47
|
+
if (isRecovery) {
|
|
48
|
+
ex = await stores.exStore.create(job, lastStatus);
|
|
49
|
+
if (recoverySlices.length) {
|
|
50
|
+
await Promise.all(recoverySlices
|
|
51
|
+
.map(({ slice, state }) => stores.stateStore.createState(ex.ex_id, slice, state, slice.error)));
|
|
52
|
+
await stores.stateStore.refresh();
|
|
53
|
+
}
|
|
54
|
+
if (createRecovery) {
|
|
55
|
+
ex = await stores.exStore.createRecoveredExecution(ex, cleanupType);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
ex = await stores.exStore.create(job);
|
|
60
|
+
}
|
|
61
|
+
if (slicerHostname && slicerPort) {
|
|
62
|
+
ex = await stores.exStore.updatePartial(ex.ex_id, async (existing) => Object.assign(existing, {
|
|
63
|
+
slicer_hostname: slicerHostname,
|
|
64
|
+
slicer_port: slicerPort,
|
|
65
|
+
_updated: makeISODate()
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
if (shutdownStores) {
|
|
69
|
+
await Promise.all([
|
|
70
|
+
stores.exStore.shutdown(true),
|
|
71
|
+
stores.jobStore.shutdown(true),
|
|
72
|
+
stores.stateStore.shutdown(true)
|
|
73
|
+
]);
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
job,
|
|
77
|
+
ex,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=job.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { isString, isArray, truncate, } from '@terascope/utils';
|
|
2
|
+
function formatVal(value) {
|
|
3
|
+
if (isString(value))
|
|
4
|
+
return `"${value}"`;
|
|
5
|
+
if (isArray(value))
|
|
6
|
+
return `[${value.join(', ')}]`;
|
|
7
|
+
return truncate(JSON.stringify(value), 30);
|
|
8
|
+
}
|
|
9
|
+
function format(input) {
|
|
10
|
+
const list = [];
|
|
11
|
+
for (const [key, value] of Object.entries(input)) {
|
|
12
|
+
list.push(`${key}: ${formatVal(value)}`);
|
|
13
|
+
}
|
|
14
|
+
return list.join(', ');
|
|
15
|
+
}
|
|
16
|
+
// TODO: fix type here
|
|
17
|
+
export function logOpStats(logger, slice, analyticsData) {
|
|
18
|
+
const { request, ...record } = slice;
|
|
19
|
+
const obj = Object.assign({}, record, analyticsData);
|
|
20
|
+
logger.info(`analytics for slice: ${format(obj)}`);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=op-analytics.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { get, isFunction, isString } from '@terascope/utils';
|
|
2
|
+
import { makeContextLogger } from '@terascope/job-components';
|
|
3
|
+
import { safeDecode } from '../../utils/encoding_utils.js';
|
|
4
|
+
export function generateWorkerId(context) {
|
|
5
|
+
const { hostname } = context.sysconfig.teraslice;
|
|
6
|
+
const clusterId = get(context, 'cluster.worker.id');
|
|
7
|
+
return `${hostname}__${clusterId}`;
|
|
8
|
+
}
|
|
9
|
+
export function makeLogger(context, moduleName, extra = {}) {
|
|
10
|
+
if (!context || !context.apis) {
|
|
11
|
+
throw new Error('makeLogger expected terafoundation context as first arg');
|
|
12
|
+
}
|
|
13
|
+
if (!moduleName || !isString(moduleName)) {
|
|
14
|
+
throw new Error('makeLogger expected module name as second arg');
|
|
15
|
+
}
|
|
16
|
+
const exAPI = context.apis.executionContext;
|
|
17
|
+
if (exAPI && isFunction(exAPI.makeLogger)) {
|
|
18
|
+
return exAPI.makeLogger(moduleName, extra);
|
|
19
|
+
}
|
|
20
|
+
const defaultContext = {};
|
|
21
|
+
if (process.env.EX) {
|
|
22
|
+
const ex = safeDecode(process.env.EX);
|
|
23
|
+
const exId = get(ex, 'ex_id');
|
|
24
|
+
const jobId = get(ex, 'job_id');
|
|
25
|
+
if (exId) {
|
|
26
|
+
defaultContext.ex_id = exId;
|
|
27
|
+
}
|
|
28
|
+
if (jobId) {
|
|
29
|
+
defaultContext.job_id = jobId;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return makeContextLogger(context, moduleName, Object.assign(defaultContext, extra));
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=terafoundation.js.map
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { get, pDelay, pRaceWithTimeout, isError, logError } from '@terascope/utils';
|
|
2
|
+
import ms from 'ms';
|
|
3
|
+
import { makeLogger } from './terafoundation.js';
|
|
4
|
+
export function waitForWorkerShutdown(context, eventName) {
|
|
5
|
+
const shutdownTimeout = get(context, 'sysconfig.teraslice.shutdown_timeout', 30000);
|
|
6
|
+
const events = context.apis.foundation.getSystemEvents();
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
const timeoutId = setTimeout(() => {
|
|
9
|
+
events.removeListener(eventName, handler);
|
|
10
|
+
reject(new Error('Timeout waiting for worker to shutdown'));
|
|
11
|
+
}, shutdownTimeout);
|
|
12
|
+
function handler(err) {
|
|
13
|
+
clearTimeout(timeoutId);
|
|
14
|
+
if (isError(err)) {
|
|
15
|
+
reject(err);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
resolve(true);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
events.once(eventName, handler);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
/* istanbul ignore next */
|
|
25
|
+
export function shutdownHandler(context, shutdownFn) {
|
|
26
|
+
const assignment = context.assignment
|
|
27
|
+
|| process.env.NODE_TYPE
|
|
28
|
+
|| process.env.assignment
|
|
29
|
+
|| 'unknown-assignment';
|
|
30
|
+
const clusteringType = get(context, 'sysconfig.teraslice.cluster_manager_type');
|
|
31
|
+
const isK8s = clusteringType === 'kubernetes' || clusteringType === 'kubernetesV2';
|
|
32
|
+
// this is native clustering only
|
|
33
|
+
const isProcessRestart = process.env.process_restart;
|
|
34
|
+
// everything but the k8s execution_controller should not be allowed be allowed to
|
|
35
|
+
// set a non-zero exit code (to avoid being restarted)
|
|
36
|
+
// This is overridden in V2 because it can restart
|
|
37
|
+
const allowNonZeroExitCode = !(isK8s
|
|
38
|
+
&& assignment === 'execution_controller'
|
|
39
|
+
&& context.sysconfig.teraslice.cluster_manager_type === 'kubernetes');
|
|
40
|
+
const api = {
|
|
41
|
+
exiting: false,
|
|
42
|
+
exit
|
|
43
|
+
};
|
|
44
|
+
const shutdownTimeout = get(context, 'sysconfig.teraslice.shutdown_timeout', 20 * 1000);
|
|
45
|
+
const events = context.apis.foundation.getSystemEvents();
|
|
46
|
+
const logger = makeLogger(context, `${assignment}:shutdown_handler`);
|
|
47
|
+
if (assignment === 'execution_controller' && isProcessRestart) {
|
|
48
|
+
logger.fatal('Execution Controller runtime error led to a restart, terminating execution with failed status, please use the recover api to return slicer to a consistent state');
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
async function flushLogs() {
|
|
52
|
+
try {
|
|
53
|
+
await logger.flush();
|
|
54
|
+
await pDelay(1000);
|
|
55
|
+
const code = process.exitCode || 0;
|
|
56
|
+
logger.debug(`flushed logs successfully, will exit with code ${code}`);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
logError(logger, err, 'flush error on shutdown');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
let startTime;
|
|
63
|
+
function exitingIn() {
|
|
64
|
+
if (!api.exiting) {
|
|
65
|
+
return `exiting in ${ms(shutdownTimeout)}...`;
|
|
66
|
+
}
|
|
67
|
+
const elapsed = Date.now() - startTime;
|
|
68
|
+
return `already shutting down, remaining ${ms(shutdownTimeout - elapsed)}`;
|
|
69
|
+
}
|
|
70
|
+
async function callShutdownFn(event, err) {
|
|
71
|
+
// avoid failing before the promse is try / catched in pRaceWithTimeout
|
|
72
|
+
await pDelay(100);
|
|
73
|
+
await shutdownFn(event, err);
|
|
74
|
+
}
|
|
75
|
+
async function shutdownWithTimeout(event, err) {
|
|
76
|
+
const timeout = shutdownTimeout - 2000;
|
|
77
|
+
await pRaceWithTimeout(callShutdownFn(event, err), timeout, (timeoutErr) => {
|
|
78
|
+
logError(logger, timeoutErr, 'shutdown error after timeout');
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
async function exit(event, err) {
|
|
82
|
+
if (api.exiting)
|
|
83
|
+
return;
|
|
84
|
+
/// Potential logic for cluster_master and asset_service
|
|
85
|
+
if (err) {
|
|
86
|
+
if (err.name.includes('Error')) {
|
|
87
|
+
setStatusCode(1);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
api.exiting = true;
|
|
91
|
+
startTime = Date.now();
|
|
92
|
+
try {
|
|
93
|
+
await shutdownWithTimeout(event, err);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
logError(logger, error, `${assignment} while shutting down`);
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
await flushLogs();
|
|
100
|
+
if (allowNonZeroExitCode) {
|
|
101
|
+
const code = process.exitCode != null ? process.exitCode : 0;
|
|
102
|
+
logger.info(`${assignment} shutdown took ${ms(Date.now() - startTime)}, exit with ${code} status code`);
|
|
103
|
+
process.exit();
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
logger.info(`${assignment} shutdown took ${ms(Date.now() - startTime)}, exit with zero status code`);
|
|
107
|
+
process.exit(0);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function setStatusCode(code) {
|
|
112
|
+
if (api.exiting)
|
|
113
|
+
return;
|
|
114
|
+
if (process.exitCode == null) {
|
|
115
|
+
process.exitCode = code;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
process.on('SIGINT', () => {
|
|
119
|
+
logger.info(`${assignment} received process:SIGINT, ${exitingIn()}`);
|
|
120
|
+
setStatusCode(0);
|
|
121
|
+
exit('SIGINT');
|
|
122
|
+
});
|
|
123
|
+
process.on('SIGTERM', () => {
|
|
124
|
+
logger.info(`${assignment} received process:SIGTERM, ${exitingIn()}`);
|
|
125
|
+
setStatusCode(0);
|
|
126
|
+
exit('SIGTERM');
|
|
127
|
+
});
|
|
128
|
+
process.on('uncaughtException', (err) => {
|
|
129
|
+
logError(logger, err, `${assignment} received an uncaughtException, ${exitingIn()}`);
|
|
130
|
+
setStatusCode(1);
|
|
131
|
+
exit('uncaughtException', err);
|
|
132
|
+
});
|
|
133
|
+
process.once('unhandledRejection', (err) => {
|
|
134
|
+
logError(logger, err, `${assignment} received an unhandledRejection, ${exitingIn()}`);
|
|
135
|
+
setStatusCode(1);
|
|
136
|
+
exit('unhandledRejection', err);
|
|
137
|
+
});
|
|
138
|
+
// See https://github.com/trentm/node-bunyan/issues/246
|
|
139
|
+
function handleStdError(err) {
|
|
140
|
+
// @ts-expect-error TODO: fix error type
|
|
141
|
+
if (err.code === 'EPIPE' || err.code === 'ERR_STREAM_DESTROYED') {
|
|
142
|
+
// ignore
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
throw err;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
process.stdout.on('error', handleStdError);
|
|
149
|
+
process.stderr.on('error', handleStdError);
|
|
150
|
+
// event is fired from terafoundation when an error occurs during instantiation of a client
|
|
151
|
+
// **DEPRECATED:** This handler should be removed on teraslice v1
|
|
152
|
+
events.once('client:initialization:error', (err) => {
|
|
153
|
+
logError(logger, err, `${assignment} received a client initialization error, ${exitingIn()}`);
|
|
154
|
+
setStatusCode(1);
|
|
155
|
+
exit('client:initialization:error', err);
|
|
156
|
+
});
|
|
157
|
+
events.once('worker:shutdown:complete', (err) => {
|
|
158
|
+
setStatusCode(0);
|
|
159
|
+
if (err) {
|
|
160
|
+
logError(logger, err, `${assignment} shutdown error, ${exitingIn()}`);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
logger.info(`${assignment} shutdown, ${exitingIn()}`);
|
|
164
|
+
}
|
|
165
|
+
exit('worker:shutdown:complete', err);
|
|
166
|
+
});
|
|
167
|
+
return api;
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=worker-shutdown.js.map
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { debugLogger, isTest } from '@terascope/utils';
|
|
3
|
+
const defaultLogger = debugLogger('metrics');
|
|
4
|
+
export class Metrics extends EventEmitter {
|
|
5
|
+
logger;
|
|
6
|
+
_intervals;
|
|
7
|
+
eventLoopInterval;
|
|
8
|
+
// TODO: fix types here
|
|
9
|
+
_typesCollectedAt;
|
|
10
|
+
gcStats;
|
|
11
|
+
eventLoopStats;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
super();
|
|
14
|
+
const argLogger = config && config.logger;
|
|
15
|
+
this.logger = argLogger
|
|
16
|
+
? argLogger.child({
|
|
17
|
+
module: 'performance:metrics'
|
|
18
|
+
})
|
|
19
|
+
: defaultLogger;
|
|
20
|
+
this.eventLoopInterval = isTest ? 100 : 5000;
|
|
21
|
+
this._intervals = [];
|
|
22
|
+
this._typesCollectedAt = {};
|
|
23
|
+
this.gcStats = null;
|
|
24
|
+
}
|
|
25
|
+
async initialize() {
|
|
26
|
+
// never cause an unwanted error
|
|
27
|
+
try {
|
|
28
|
+
const module = await import('gc-stats');
|
|
29
|
+
this.gcStats = module.default();
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
this.logger.error(err, 'Failure to construct gc-stats');
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
this.eventLoopStats = await import('event-loop-stats');
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
this.logger.error(err, 'Failure to construct event-loop-stats');
|
|
39
|
+
}
|
|
40
|
+
const gcEnabled = this.gcStats != null;
|
|
41
|
+
const loopEnabled = this.eventLoopStats != null;
|
|
42
|
+
this.logger.info('initializing performance metrics', {
|
|
43
|
+
gcEnabled,
|
|
44
|
+
loopEnabled
|
|
45
|
+
});
|
|
46
|
+
if (this.gcStats !== null) {
|
|
47
|
+
// https://github.com/dainis/node-gcstats#property-insights
|
|
48
|
+
const typesToName = {
|
|
49
|
+
1: 'Scavenge',
|
|
50
|
+
2: 'MarkSweepCompact',
|
|
51
|
+
4: 'IncrementalMarking',
|
|
52
|
+
8: 'WeakPhantomCallbackProcessing',
|
|
53
|
+
15: 'All'
|
|
54
|
+
};
|
|
55
|
+
this.gcStats.on('stats', (metrics) => {
|
|
56
|
+
// never cause an unwanted error
|
|
57
|
+
if (!metrics) {
|
|
58
|
+
this.logger.warn('invalid metrics received for gc stats', metrics);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const typeName = typesToName[metrics.gctype];
|
|
62
|
+
this._emitMetric('gc-stats', Object.assign({ typeName }, metrics));
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (loopEnabled) {
|
|
66
|
+
// https://github.com/bripkens/event-loop-stats#property-insights
|
|
67
|
+
this._intervals.push(setInterval(() => {
|
|
68
|
+
// never cause an unwanted error
|
|
69
|
+
let metrics;
|
|
70
|
+
try {
|
|
71
|
+
metrics = this.eventLoopStats.sense();
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
this.logger.error(err, 'failure getting for event-loop-stats');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (!metrics) {
|
|
78
|
+
this.logger.warn('invalid metrics received for event-loop-stats', metrics);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
this._emitMetric('event-loop-stats', metrics);
|
|
82
|
+
}, this.eventLoopInterval));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async shutdown() {
|
|
86
|
+
try {
|
|
87
|
+
this._intervals.forEach(clearInterval);
|
|
88
|
+
this._intervals = [];
|
|
89
|
+
this.removeAllListeners();
|
|
90
|
+
this._typesCollectedAt = {};
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
this.logger.debug(err, 'failure shutting down metrics');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
_emitMetric(type, metrics) {
|
|
97
|
+
const lastCollectedAt = this._typesCollectedAt[type] || Date.now();
|
|
98
|
+
const msg = {
|
|
99
|
+
type,
|
|
100
|
+
timeSinceLast: Date.now() - lastCollectedAt,
|
|
101
|
+
metrics
|
|
102
|
+
};
|
|
103
|
+
this._typesCollectedAt[type] = Date.now();
|
|
104
|
+
this.emit('metric', msg);
|
|
105
|
+
this.logger.info(msg, `${type} performance metrics`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=index.js.map
|