dcp-worker 3.2.30-9 → 3.2.30
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/.gitlab-ci.yml +1 -0
- package/bin/dcp-worker +160 -95
- package/docs/CODEOWNERS +2 -0
- package/etc/dcp-worker-config.js +1 -1
- package/etc/dcp-worker-config.js.md5 +1 -1
- package/lib/blessed-components/index.js +1 -0
- package/lib/blessed-components/log.js +1 -0
- package/lib/blessed-components/sandboxes.js +10 -6
- package/lib/check-scheduler-version.js +1 -0
- package/lib/dashboard-tui.js +231 -0
- package/lib/default-ui-events.js +171 -0
- package/lib/pidfile.js +1 -1
- package/lib/remote-console.js +10 -2
- package/lib/startWorkerLogger.js +98 -62
- package/lib/utils.js +28 -0
- package/lib/worker-loggers/console.js +24 -108
- package/lib/worker-loggers/dashboard.js +32 -172
- package/lib/worker-loggers/event-log.js +28 -60
- package/lib/worker-loggers/logfile.js +57 -83
- package/lib/worker-loggers/syslog.js +41 -63
- package/package.json +16 -7
- package/lib/worker-loggers/common-types.js +0 -24
package/.gitlab-ci.yml
CHANGED
package/bin/dcp-worker
CHANGED
|
@@ -4,25 +4,26 @@
|
|
|
4
4
|
* Standalone NodeJS DCP Worker
|
|
5
5
|
*
|
|
6
6
|
* @author Ryan Rossiter, ryan@kingsds.network
|
|
7
|
+
* Paul, paul@distributive.network
|
|
8
|
+
* Wes Garland, wes@distributive.network
|
|
9
|
+
*
|
|
7
10
|
* @date April 2020
|
|
11
|
+
* April-May 2023
|
|
12
|
+
* May-June 2023
|
|
8
13
|
*/
|
|
9
14
|
'use strict';
|
|
10
15
|
|
|
16
|
+
var worker;
|
|
17
|
+
|
|
11
18
|
const process = require('process');
|
|
12
19
|
const fs = require('fs');
|
|
20
|
+
const path = require('path');
|
|
13
21
|
const crypto = require('crypto');
|
|
14
22
|
const chalk = require('chalk');
|
|
23
|
+
const telnetd = require('../lib/remote-console');
|
|
24
|
+
const utils = require('../lib/utils');
|
|
15
25
|
|
|
16
26
|
const configName = process.env.DCP_CONFIG || '../etc/dcp-worker-config';
|
|
17
|
-
var worker, dcpConfig, debugging;
|
|
18
|
-
|
|
19
|
-
const debug = (...args) => {
|
|
20
|
-
if (!debugging)
|
|
21
|
-
debugging = require('dcp/internal/debugging').scope('dcp-worker');
|
|
22
|
-
if (debugging())
|
|
23
|
-
console.debug('dcp-worker:', ...args);
|
|
24
|
-
};
|
|
25
|
-
|
|
26
27
|
const EXIT_UNHANDLED = 5;
|
|
27
28
|
|
|
28
29
|
/* Setup the telnet REPL up early to ensure early-failure log messages are captured */
|
|
@@ -34,13 +35,15 @@ const replHelpers = {
|
|
|
34
35
|
},
|
|
35
36
|
commands: {
|
|
36
37
|
report: printReport,
|
|
37
|
-
kill:
|
|
38
|
+
kill: processExit,
|
|
38
39
|
die: () => worker && worker.stop()
|
|
39
40
|
},
|
|
40
41
|
};
|
|
41
|
-
|
|
42
|
+
telnetd.init(replHelpers);
|
|
42
43
|
|
|
43
|
-
/* Initialize dcp-client with local config defaults and run the main function. DCP_CONFIG_COOKIE becomes dcpConfig.cookie.
|
|
44
|
+
/* Initialize dcp-client with local config defaults and run the main function. DCP_CONFIG_COOKIE becomes dcpConfig.cookie.
|
|
45
|
+
* And dcpConfig is defined as a side effect of initializing dcp-client.
|
|
46
|
+
*/
|
|
44
47
|
process.env.DCP_CONFIG_COOKIE = (Math.random().toString(16)).slice(2) + '-' + process.pid + '-' + Date.now();
|
|
45
48
|
require('dcp-client').init({ configName }).then(main).catch(handleUnhandled);
|
|
46
49
|
|
|
@@ -48,7 +51,6 @@ function parseCliArgs()
|
|
|
48
51
|
{
|
|
49
52
|
var defaultPidFileName;
|
|
50
53
|
|
|
51
|
-
dcpConfig = require('dcp/dcp-config');
|
|
52
54
|
defaultPidFileName = require('../lib/pidfile').getDefaultPidFileName(dcpConfig.worker.pidfile);
|
|
53
55
|
|
|
54
56
|
const cliArgs = require('dcp/cli')
|
|
@@ -67,7 +69,6 @@ function parseCliArgs()
|
|
|
67
69
|
alias: 'd',
|
|
68
70
|
describe: 'default proportion of CPU,GPU to use when cores not specified',
|
|
69
71
|
type: 'string',
|
|
70
|
-
default: JSON.stringify(dcpConfig.worker.defaultCoreDensity),
|
|
71
72
|
},
|
|
72
73
|
verbose: {
|
|
73
74
|
alias: 'v',
|
|
@@ -98,18 +99,21 @@ function parseCliArgs()
|
|
|
98
99
|
},
|
|
99
100
|
priorityOnly: {
|
|
100
101
|
alias: 'P',
|
|
102
|
+
hidden: true,
|
|
101
103
|
describe: 'Set the priority mode [deprecated]',
|
|
102
104
|
type: 'boolean',
|
|
103
105
|
default: false
|
|
104
106
|
},
|
|
105
107
|
'job-id': {
|
|
106
108
|
alias: 'j',
|
|
109
|
+
hidden: true,
|
|
107
110
|
describe: 'Restrict worker to a specific job (use N times for N jobs)',
|
|
108
111
|
type: 'array',
|
|
109
112
|
},
|
|
110
113
|
|
|
111
114
|
join: {
|
|
112
115
|
alias: 'g',
|
|
116
|
+
hidden: true,
|
|
113
117
|
describe: 'Join compute group; the format is "joinKey,joinSecret" or "joinKey,eh1-joinHash"',
|
|
114
118
|
type: 'array'
|
|
115
119
|
},
|
|
@@ -120,22 +124,27 @@ function parseCliArgs()
|
|
|
120
124
|
|
|
121
125
|
leavePublicGroup: {
|
|
122
126
|
type: 'boolean',
|
|
123
|
-
|
|
124
|
-
|
|
127
|
+
hidden: true,
|
|
128
|
+
describe: 'Do not fetch slices from public compute group.',
|
|
129
|
+
default: undefined,
|
|
125
130
|
},
|
|
131
|
+
|
|
126
132
|
publicGroupFallback: {
|
|
133
|
+
hidden: true,
|
|
127
134
|
describe: 'If set, worker will prefer private groups but fall back on the public group if no preferred work is available',
|
|
128
135
|
type: 'boolean',
|
|
129
|
-
default: '
|
|
130
|
-
defaultDescription:
|
|
136
|
+
default: 'undefined',
|
|
137
|
+
defaultDescription: undefined,
|
|
131
138
|
},
|
|
132
139
|
|
|
133
140
|
identityKey: {
|
|
141
|
+
hidden: true,
|
|
134
142
|
describe: 'Identity key, in hex format',
|
|
135
143
|
type: 'string',
|
|
136
144
|
group: 'Identity options',
|
|
137
145
|
},
|
|
138
146
|
identityKeystore: {
|
|
147
|
+
hidden: true,
|
|
139
148
|
describe: 'Identity keystore, in json format',
|
|
140
149
|
type: 'string',
|
|
141
150
|
group: 'Identity options',
|
|
@@ -147,30 +156,40 @@ function parseCliArgs()
|
|
|
147
156
|
group: 'Output options',
|
|
148
157
|
},
|
|
149
158
|
eventDebug: {
|
|
150
|
-
|
|
159
|
+
hidden: true,
|
|
151
160
|
describe: 'If set, dump all sandbox and worker events',
|
|
152
161
|
},
|
|
153
162
|
|
|
154
163
|
logfile: {
|
|
155
|
-
describe: 'Path to log file
|
|
164
|
+
describe: 'Path to log file',
|
|
156
165
|
type: 'string',
|
|
157
166
|
group: 'Log File output options',
|
|
167
|
+
default: path.resolve('../log/dcp-worker.log'),
|
|
158
168
|
},
|
|
159
169
|
syslogAddress: {
|
|
160
|
-
describe: 'Address of
|
|
170
|
+
describe: 'Address of syslog server',
|
|
161
171
|
type: 'string',
|
|
162
172
|
group: 'Syslog output options',
|
|
173
|
+
default: 'loghost',
|
|
174
|
+
},
|
|
175
|
+
syslogFacility: {
|
|
176
|
+
describe: 'Name of syslog facility',
|
|
177
|
+
type: 'string',
|
|
178
|
+
group: 'Syslog output options',
|
|
179
|
+
default: 'local7',
|
|
163
180
|
},
|
|
164
181
|
syslogTransport: {
|
|
165
|
-
describe: 'Transport to connect to
|
|
182
|
+
describe: 'Transport to connect to use for syslog',
|
|
166
183
|
type: 'string',
|
|
167
|
-
choices: ['udp','tcp'],
|
|
184
|
+
choices: ['udp','tcp','unix','tls'],
|
|
168
185
|
group: 'Syslog output options',
|
|
186
|
+
default: 'udp',
|
|
169
187
|
},
|
|
170
188
|
syslogPort: {
|
|
171
|
-
describe: 'UDP/TCP port
|
|
189
|
+
describe: 'UDP/TCP port to use for syslog',
|
|
172
190
|
type: 'number',
|
|
173
191
|
group: 'Syslog output options',
|
|
192
|
+
default: 514,
|
|
174
193
|
},
|
|
175
194
|
|
|
176
195
|
allowedOrigins: {
|
|
@@ -202,8 +221,8 @@ function parseCliArgs()
|
|
|
202
221
|
|
|
203
222
|
if (cliArgs.dumpConfig)
|
|
204
223
|
{
|
|
205
|
-
console.
|
|
206
|
-
|
|
224
|
+
console.log(JSON.stringify(require('dcp/dcp-config'), null, 2));
|
|
225
|
+
processExit(0);
|
|
207
226
|
}
|
|
208
227
|
|
|
209
228
|
return cliArgs;
|
|
@@ -228,6 +247,20 @@ function addConfig(target, ...objs)
|
|
|
228
247
|
Object.assign(target, tmp);
|
|
229
248
|
}
|
|
230
249
|
|
|
250
|
+
/**
|
|
251
|
+
* Replacement for process.exit() that tries to increase the probability
|
|
252
|
+
* that remote log messages will make it out over the network.
|
|
253
|
+
*/
|
|
254
|
+
function processExit()
|
|
255
|
+
{
|
|
256
|
+
logClosing('debug', 'Exit Code:', process.exitCode || 0);
|
|
257
|
+
if (console.close)
|
|
258
|
+
console.close();
|
|
259
|
+
setImmediate(() => {
|
|
260
|
+
process.exit.apply(null, arguments);
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
231
264
|
/**
|
|
232
265
|
* Main program entry point. Assumes DCP client is already initialized and console logging is ready.
|
|
233
266
|
*/
|
|
@@ -235,21 +268,22 @@ async function main()
|
|
|
235
268
|
{
|
|
236
269
|
const wallet = require('dcp/wallet');
|
|
237
270
|
const DCPWorker = require('dcp/worker').Worker;
|
|
238
|
-
const { startWorkerLogger } = require('../lib/startWorkerLogger');
|
|
239
271
|
const cliArgs = parseCliArgs();
|
|
240
272
|
const sawOptions = {
|
|
241
273
|
hostname: cliArgs.hostname,
|
|
242
274
|
port: cliArgs.port
|
|
243
275
|
};
|
|
244
276
|
|
|
245
|
-
|
|
277
|
+
telnetd.setMainEval(function mainEval() { return eval(arguments[0]) }); // eslint-disable-line no-eval
|
|
278
|
+
require('../lib/startWorkerLogger').init(cliArgs); /* Start remote logger as early as possible */
|
|
279
|
+
verifyDefaultConfigIntegrity(); /* Bail before TUI & as early as possible if bad conf */
|
|
246
280
|
|
|
247
281
|
process.on('SIGINT', handleSigDeath);
|
|
248
282
|
process.on('SIGTERM', handleSigDeath);
|
|
249
283
|
process.on('SIGQUIT', handleSigDeath);
|
|
250
284
|
process.on('unhandledRejection', handleUnhandled);
|
|
251
285
|
process.on('uncaughtException', handleUnhandled);
|
|
252
|
-
|
|
286
|
+
|
|
253
287
|
let paymentAddress = false
|
|
254
288
|
|| cliArgs.paymentAddress
|
|
255
289
|
|| dcpConfig.worker.paymentAddress
|
|
@@ -260,7 +294,7 @@ async function main()
|
|
|
260
294
|
if (cliArgs.pidFile)
|
|
261
295
|
require('../lib/pidfile').write(cliArgs.pidFile);
|
|
262
296
|
|
|
263
|
-
/* Figure out
|
|
297
|
+
/* Figure out the worker's identity and put that keystore in the wallet */
|
|
264
298
|
let identityKeystore = false;
|
|
265
299
|
if (cliArgs.identityKey)
|
|
266
300
|
identityKeystore = await new wallet.IdKeystore(cliArgs.identityKey, '');
|
|
@@ -278,11 +312,14 @@ async function main()
|
|
|
278
312
|
* which were derived from dcpConfig in the first place. defaultOptions are overrideable by the usual
|
|
279
313
|
* dcpConfig mechanisms, but since they are dynamic (or non-user-facing) they don't come from the
|
|
280
314
|
* etc/dcp-worker-config.js file that ships with the work.
|
|
315
|
+
*
|
|
316
|
+
* It is important to never disable leavePublicGroup as a side effect of any other operation, or
|
|
317
|
+
* slight configuration errors could have large security impacts.
|
|
281
318
|
*/
|
|
282
319
|
const dcpWorkerOptions = dcpConfig.worker;
|
|
283
320
|
const forceOptions = {
|
|
284
321
|
paymentAddress,
|
|
285
|
-
|
|
322
|
+
maxWorkingSandboxes: cliArgs.cores,
|
|
286
323
|
};
|
|
287
324
|
const defaultOptions = {
|
|
288
325
|
sandboxOptions: {
|
|
@@ -290,9 +327,21 @@ async function main()
|
|
|
290
327
|
},
|
|
291
328
|
};
|
|
292
329
|
|
|
330
|
+
if (cliArgs.leavePublicGroup !== undefined)
|
|
331
|
+
forceOptions.leavePublicGroup = mkBool(cliArgs.leavePublicGroup);
|
|
332
|
+
if (cliArgs.publicGroupFallback !== undefined)
|
|
333
|
+
forceOptions.publicGroupFallback = mkBool(cliArgs.publicGroupFallback);
|
|
334
|
+
|
|
293
335
|
addConfig(dcpWorkerOptions, defaultOptions, dcpConfig.worker, forceOptions);
|
|
294
336
|
processCoresAndDensity(dcpWorkerOptions, cliArgs);
|
|
295
337
|
|
|
338
|
+
/* Support magic value used by Windows screensaver configuration /wg June 2023 */
|
|
339
|
+
if (dcpWorkerOptions.leavePublicGroup === 'fallback')
|
|
340
|
+
{
|
|
341
|
+
dcpWorkerOptions.publicGroupFallback = true;
|
|
342
|
+
dcpWorkerOptions.leavePublicGroup = undefined;
|
|
343
|
+
}
|
|
344
|
+
|
|
296
345
|
/* cliArgs.join is the list of compute groups to join */
|
|
297
346
|
if (cliArgs.join && cliArgs.join.length)
|
|
298
347
|
{
|
|
@@ -325,47 +374,44 @@ async function main()
|
|
|
325
374
|
dcpWorkerOptions.watchdogInterval = cliArgs.watchdogInterval;
|
|
326
375
|
|
|
327
376
|
worker = new DCPWorker(identityKeystore, dcpWorkerOptions);
|
|
328
|
-
worker.on('error',
|
|
329
|
-
worker.on('warning', (...payload) => console.warn(...payload));
|
|
377
|
+
worker.on('error', (...payload) => console.error(...payload));
|
|
378
|
+
worker.on('warning', (...payload) => console.warn (...payload));
|
|
379
|
+
worker.on('stop', () => { console.log('Worker is stopping') });
|
|
380
|
+
worker.on('end', () => { logClosing('log', 'Worker has stopped') });
|
|
381
|
+
require('../lib/default-ui-events').hook(worker, cliArgs);
|
|
330
382
|
|
|
383
|
+
if (cliArgs.outputMode === 'dashboard')
|
|
384
|
+
require('../lib/dashboard-tui').init(worker, cliArgs);
|
|
385
|
+
|
|
331
386
|
/* Let incorrect event-loop references keep us alive when linked with a debug library, but
|
|
332
387
|
* exit quickly/accurately for production code even when the library isn't perfect.
|
|
333
388
|
*/
|
|
334
389
|
if (require('dcp/build').config.build !== 'debug')
|
|
335
|
-
worker.on('end',
|
|
390
|
+
worker.on('end', processExit);
|
|
336
391
|
else
|
|
337
|
-
worker.on('end', () => setTimeout(
|
|
392
|
+
worker.on('end', () => setTimeout(processExit, getCleanupTimeoutMs()).unref());
|
|
338
393
|
|
|
339
394
|
if (cliArgs.eventDebug)
|
|
340
395
|
worker.enableDebugEvents = true;
|
|
341
396
|
|
|
342
|
-
|
|
343
|
-
worker.on('end', () => { logClosing('log', 'Worker has stopped') });
|
|
344
|
-
startWorkerLogger(worker, cliArgs);
|
|
345
|
-
|
|
346
|
-
require('../lib/remote-console').setMainEval(function mainEval() { return eval(arguments[0]) });
|
|
347
|
-
|
|
348
|
-
// Activate public group fallback
|
|
349
|
-
// If requested by CLI
|
|
350
|
-
// OR if requested by dcpConfig and not forbidden by the cli
|
|
351
|
-
if (cliArgs.publicGroupFallback
|
|
352
|
-
|| (dcpConfig.worker?.leavePublicGroup === 'fallback'
|
|
353
|
-
&& typeof cliArgs.publicGroupFallback !== false))
|
|
397
|
+
if (dcpWorkerOptions.publicGroupFallback)
|
|
354
398
|
{
|
|
355
|
-
dcpWorkerOptions.
|
|
356
|
-
|
|
357
|
-
// If local config blocks the public group, then complain instead of activating fallback
|
|
358
|
-
if (dcpConfig.worker?.leavePublicGroup === true)
|
|
359
|
-
{
|
|
360
|
-
console.warn('* Public Group fallback has been requested, but the public group is blocked by local configuration');
|
|
361
|
-
}
|
|
399
|
+
if (dcpWorkerOptions.leavePublicGroup)
|
|
400
|
+
console.warn(' ! Public Group fallback has been requested, but the public group is blocked by local configuration');
|
|
362
401
|
else
|
|
363
402
|
{
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
403
|
+
/* Enable public group fallback - this currently works by enabling or disabling the public group
|
|
404
|
+
* on the next fetch based on whether or not the most recent fetch was an empty task or not.
|
|
405
|
+
*/
|
|
406
|
+
worker.on('fetch', fetchEventHandler);
|
|
407
|
+
|
|
408
|
+
function fetchEventHandler(ev)
|
|
409
|
+
{
|
|
410
|
+
if (ev instanceof Error)
|
|
411
|
+
console.error('Error fetching task:', ev);
|
|
412
|
+
else
|
|
413
|
+
dcpWorkerOptions.leavePublicGroup = Boolean(utils.slicesFetched(ev) > 0);
|
|
414
|
+
}
|
|
369
415
|
}
|
|
370
416
|
}
|
|
371
417
|
|
|
@@ -391,21 +437,23 @@ async function main()
|
|
|
391
437
|
|
|
392
438
|
if (dcpWorkerOptions.jobAddresses?.length > 0)
|
|
393
439
|
introBanner += ` * Processing only ${qty(dcpWorkerOptions.jobAddresses, 'job')} ` + dcpWorkerOptions.jobAddresses.join(', ') + '\n';
|
|
394
|
-
if (dcpWorkerOptions.computeGroups
|
|
440
|
+
if (dcpWorkerOptions.computeGroups && Object.keys(dcpWorkerOptions.computeGroups).length > 0)
|
|
395
441
|
introBanner += ` . Joining compute ${qty(dcpWorkerOptions.computeGroups, 'group')} ` + dcpWorkerOptions.computeGroups.map(el => el.joinKey).join(', ') + '\n';
|
|
396
442
|
if (dcpWorkerOptions.publicGroupFallback)
|
|
397
443
|
introBanner += ' . Falling back on public group when preferred groups have no work' + '\n';
|
|
398
|
-
|
|
444
|
+
if (dcpWorkerOptions.leavePublicGroup)
|
|
399
445
|
introBanner += ' . Leaving the public compute group' + '\n';
|
|
400
446
|
if (dcpWorkerOptions.cores)
|
|
401
|
-
introBanner += ` .
|
|
447
|
+
introBanner += ` . Configured Cores: ${dcpWorkerOptions.cores.cpu},${dcpWorkerOptions.cores.gpu}\n`
|
|
402
448
|
else
|
|
403
449
|
introBanner += ` . Target core density: ${JSON.stringify(dcpWorkerOptions.defaultCoreDensity)}\n`;
|
|
404
450
|
if (cliArgs.verbose)
|
|
405
451
|
introBanner += ` + Verbosity level: ${cliArgs.verbose}` + '\n';
|
|
406
452
|
if (cliArgs.eventDebug)
|
|
407
453
|
introBanner += ' + Event debug on' + '\n';
|
|
408
|
-
|
|
454
|
+
if (telnetd.hasOwnProperty('port'))
|
|
455
|
+
introBanner += ` ! telnetd listening on port ${telnetd.port}\n`;
|
|
456
|
+
|
|
409
457
|
introBanner += ' . Supervisor version: ' + worker.supervisorVersion;
|
|
410
458
|
introBanner += ' . Output mode: ' + cliArgs.outputMode + '\n';
|
|
411
459
|
introBanner += ' * Ready' + '\n';
|
|
@@ -418,7 +466,7 @@ async function main()
|
|
|
418
466
|
if (cliArgs.outputMode !== 'dashboard')
|
|
419
467
|
setInterval(printReport, parseFloat(cliArgs.reportInterval) * 1000).unref();
|
|
420
468
|
else
|
|
421
|
-
console.
|
|
469
|
+
console.warn('Ignoring --reportInterval in dashboard output mode');
|
|
422
470
|
}
|
|
423
471
|
|
|
424
472
|
/* Start the worker. Normal process exit happens by virtue of the worker<end> event */
|
|
@@ -445,21 +493,22 @@ function processCoresAndDensity (dcpWorkerOptions, cliArgs)
|
|
|
445
493
|
|
|
446
494
|
const parseArg = (which) => {
|
|
447
495
|
if (!cliArgs[which])
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
496
|
+
dcpWorkerOptions[which] = defaultTargets[which];
|
|
497
|
+
else
|
|
498
|
+
{
|
|
499
|
+
const [cpu, gpu] = cliArgs[which].split(',');
|
|
500
|
+
dcpWorkerOptions[which] = { cpu: Number(cpu || defaultTargets[which].cpu),
|
|
501
|
+
gpu: Number(gpu || defaultTargets[which].gpu) };
|
|
502
|
+
}
|
|
454
503
|
};
|
|
455
504
|
|
|
456
505
|
parseArg('density');
|
|
457
506
|
parseArg('cores');
|
|
458
507
|
|
|
459
508
|
if (dcpWorkerOptions.cores)
|
|
460
|
-
debug('cores =
|
|
461
|
-
|
|
462
|
-
debug('core density =
|
|
509
|
+
debugging() && console.debug('dcp-worker: cores =', dcpWorkerOptions.cores);
|
|
510
|
+
if (dcpWorkerOptions.density)
|
|
511
|
+
debugging() && console.debug('dcp-worker: core density =', dcpWorkerOptions.density);
|
|
463
512
|
}
|
|
464
513
|
|
|
465
514
|
/**
|
|
@@ -470,9 +519,7 @@ function logClosing(facility, ...message)
|
|
|
470
519
|
{
|
|
471
520
|
var screen = require('../lib/worker-loggers/dashboard').screen;
|
|
472
521
|
|
|
473
|
-
if (
|
|
474
|
-
console[facility](message);
|
|
475
|
-
else
|
|
522
|
+
if (screen)
|
|
476
523
|
{
|
|
477
524
|
/* Turn off fullscreen TUI and resume "normal" console logging.
|
|
478
525
|
* FUTURE: dashboard API should know how to unregister its hook so that we don't have to clobber
|
|
@@ -481,10 +528,11 @@ function logClosing(facility, ...message)
|
|
|
481
528
|
screen.log(...message);
|
|
482
529
|
screen.destroy();
|
|
483
530
|
screen = false;
|
|
484
|
-
console = new (require('console').Console)(process);
|
|
485
|
-
|
|
486
|
-
console[facility].call(null, ...message);
|
|
531
|
+
console = new (require('console').Console)(process); // eslint-disable-line no-global-assign
|
|
532
|
+
telnetd.reintercept();
|
|
487
533
|
}
|
|
534
|
+
|
|
535
|
+
console[facility](...message);
|
|
488
536
|
}
|
|
489
537
|
|
|
490
538
|
/**
|
|
@@ -493,7 +541,7 @@ function logClosing(facility, ...message)
|
|
|
493
541
|
* the worker must be restarted. This handler does its best to report the rejection and give the worker a few
|
|
494
542
|
* seconds in which to attempt to return slices to the scheduler before it gives up completely.
|
|
495
543
|
*/
|
|
496
|
-
|
|
544
|
+
function handleUnhandled(error)
|
|
497
545
|
{
|
|
498
546
|
var _worker = worker;
|
|
499
547
|
worker = false;
|
|
@@ -502,21 +550,21 @@ async function handleUnhandled(error)
|
|
|
502
550
|
|
|
503
551
|
try
|
|
504
552
|
{
|
|
505
|
-
logClosing(error);
|
|
506
|
-
} catch(e) {}
|
|
553
|
+
logClosing('error', error);
|
|
554
|
+
} catch(e) {} // eslint-disable-line no-empty
|
|
507
555
|
|
|
508
556
|
if (!_worker)
|
|
509
557
|
console.error('trapped unhandled error:', error)
|
|
510
558
|
else
|
|
511
559
|
{
|
|
512
560
|
console.error('trapped unhandled error -- stopping worker:', error);
|
|
513
|
-
_worker.on('end',
|
|
561
|
+
_worker.on('end', processExit);
|
|
514
562
|
_worker.stop();
|
|
515
563
|
}
|
|
516
564
|
|
|
517
565
|
setTimeout(() => {
|
|
518
566
|
logClosing('error', 'handleFatalError timeout - exiting now');
|
|
519
|
-
|
|
567
|
+
processExit();
|
|
520
568
|
}, getCleanupTimeoutMs()).unref();
|
|
521
569
|
|
|
522
570
|
try {
|
|
@@ -526,7 +574,7 @@ async function handleUnhandled(error)
|
|
|
526
574
|
fs.appendFileSync(process.env.DCP_WORKER_UNHANDLED_REJECTION_LOG,
|
|
527
575
|
`${Date.now()}: ${error.message}\n${error.stack}\n\n`);
|
|
528
576
|
}
|
|
529
|
-
} catch(e) {}
|
|
577
|
+
} catch(e) {} // eslint-disable-line no-empty
|
|
530
578
|
}
|
|
531
579
|
|
|
532
580
|
/** print the slice report via console.log */
|
|
@@ -584,14 +632,14 @@ function sliceReport()
|
|
|
584
632
|
|
|
585
633
|
report += ('Progress:') + '\n';
|
|
586
634
|
worker.workingSandboxes.forEach(sb => {
|
|
587
|
-
const jobName = sb.job
|
|
635
|
+
const jobName = sb.job?.public?.name || `idek (${sb.jobAddress})`;
|
|
588
636
|
let el = Date.now() - sb.sliceStartTime;
|
|
589
637
|
const t = el < 1000000
|
|
590
638
|
? toInterval(el)
|
|
591
639
|
: 'new';
|
|
592
640
|
|
|
593
641
|
el = sb.progressReports && sb.progressReports.last
|
|
594
|
-
? Date.now() - (sb.sliceStartTime + sb.progressReports.last
|
|
642
|
+
? Date.now() - (sb.sliceStartTime + (sb.progressReports.last?.timestamp ?? 0))
|
|
595
643
|
: 0;
|
|
596
644
|
const pct = (typeof sb.progress) === 'number'
|
|
597
645
|
? `${Number(sb.progress).toFixed(0).padStart(2)}%`
|
|
@@ -623,14 +671,14 @@ function handleSigDeath(signalName, signal)
|
|
|
623
671
|
process.off(signalName, handleSigDeath);
|
|
624
672
|
|
|
625
673
|
if (!worker)
|
|
626
|
-
console.
|
|
674
|
+
console.warn(`trapped ${signalName}, signal ${signal}`);
|
|
627
675
|
else
|
|
628
676
|
{
|
|
629
|
-
console.
|
|
677
|
+
console.warn(`trapped ${signalName}, signal ${signal} -- stopping worker`);
|
|
630
678
|
worker.stop(signalName === 'SIGQUIT');
|
|
631
679
|
}
|
|
632
680
|
|
|
633
|
-
setTimeout(() =>
|
|
681
|
+
setTimeout(() => processExit(signal - 128), getCleanupTimeoutMs()).unref();
|
|
634
682
|
}
|
|
635
683
|
|
|
636
684
|
/**
|
|
@@ -650,7 +698,7 @@ function getCleanupTimeoutMs()
|
|
|
650
698
|
cleanupTimeout = defaultCT;
|
|
651
699
|
if (!getCleanupTimeoutMs.warned)
|
|
652
700
|
{
|
|
653
|
-
console.
|
|
701
|
+
console.error(`warning: dcpConfig.worker.cleanupTimeout is not a number (${dcpConfig.worker.cleanupTimeout})`);
|
|
654
702
|
getCleanupTimeoutMs.warned = true;
|
|
655
703
|
}
|
|
656
704
|
}
|
|
@@ -672,14 +720,14 @@ function verifyDefaultConfigIntegrity()
|
|
|
672
720
|
|
|
673
721
|
if (!fs.existsSync(md5sumPath))
|
|
674
722
|
{
|
|
675
|
-
console.
|
|
723
|
+
console.error(chalk.bold.red(` ! warning: ${md5sumPath} not found; cannot verify configuration integrity`));
|
|
676
724
|
require('dcp/utils').sleep(2);
|
|
677
725
|
}
|
|
678
726
|
else
|
|
679
727
|
{
|
|
680
728
|
const originalMd5sum = fs.readFileSync(md5sumPath, 'ascii');
|
|
681
729
|
const actualMd5sum = crypto.createHash('md5')
|
|
682
|
-
.update(fs.readFileSync(workerConfPath
|
|
730
|
+
.update(fs.readFileSync(workerConfPath))
|
|
683
731
|
.digest('hex');
|
|
684
732
|
|
|
685
733
|
if (!originalMd5sum.startsWith(actualMd5sum))
|
|
@@ -694,7 +742,7 @@ function verifyDefaultConfigIntegrity()
|
|
|
694
742
|
console.warn(' - the Windows Registry');
|
|
695
743
|
|
|
696
744
|
if (require('dcp/build').config.build !== 'debug')
|
|
697
|
-
|
|
745
|
+
processExit(1);
|
|
698
746
|
|
|
699
747
|
console.log(chalk.bold.red.inverse("If this wasn't a debug build, the worker would exit now."));
|
|
700
748
|
require('dcp/utils').sleep(2);
|
|
@@ -704,6 +752,23 @@ function verifyDefaultConfigIntegrity()
|
|
|
704
752
|
if (dcpConfig.cookie !== process.env.DCP_CONFIG_COOKIE || !dcpConfig.cookie)
|
|
705
753
|
{
|
|
706
754
|
console.error(' ! DCP Worker default configuration was not loaded; exiting.');
|
|
707
|
-
|
|
755
|
+
processExit(1);
|
|
708
756
|
}
|
|
709
757
|
}
|
|
758
|
+
|
|
759
|
+
/* thunk - ensures global debugging() symbol always available even if called before dcp-client init */
|
|
760
|
+
function debugging()
|
|
761
|
+
{
|
|
762
|
+
require('dcp-client');
|
|
763
|
+
debugging = require('dcp/internal/debugging').scope('dcp-worker');
|
|
764
|
+
return debugging.apply(this, arguments);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Cast b to boolean such that 'false' becomes false, falsey things become false, and everything else
|
|
769
|
+
* becomes true.
|
|
770
|
+
*/
|
|
771
|
+
function mkBool(b)
|
|
772
|
+
{
|
|
773
|
+
return Boolean(b) && (b !== 'false');
|
|
774
|
+
}
|
package/docs/CODEOWNERS
CHANGED
|
@@ -18,9 +18,11 @@
|
|
|
18
18
|
/package-lock.json @eroosenmaallen
|
|
19
19
|
|
|
20
20
|
[Wes]
|
|
21
|
+
/npm-hooks/ @wesgarland
|
|
21
22
|
/README.md @wesgarland
|
|
22
23
|
/docs/ @wesgarland
|
|
23
24
|
/.eslintrc.json @wesgarland
|
|
25
|
+
/.npmrc @wesgarland
|
|
24
26
|
/.tidelift @wesgarland
|
|
25
27
|
/lib/ @wesgarland
|
|
26
28
|
/LICENSE.md @wesgarland
|
package/etc/dcp-worker-config.js
CHANGED
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
// keystore('~/.dcp/scott'),
|
|
50
50
|
],
|
|
51
51
|
|
|
52
|
-
jobAddresses:
|
|
52
|
+
jobAddresses: false, /* If specified, restrict the worker to only these jobs */
|
|
53
53
|
paymentAddress: undefined, /* Bank account where earned funds are transfered if not specified on command-line */
|
|
54
54
|
},
|
|
55
55
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
4d49057dd014344e4be5a266e9754824
|
|
2
2
|
### DO NOT MODIFY THIS FILE!!! ###
|
|
@@ -67,11 +67,7 @@ class Sandboxes extends Box {
|
|
|
67
67
|
update(data=this.data) {
|
|
68
68
|
this.data = data;
|
|
69
69
|
for (let i = 0; i < this.data.length; i++) {
|
|
70
|
-
|
|
71
|
-
this.updateProgressBar(i, this.data[i]);
|
|
72
|
-
} else {
|
|
73
|
-
this.createProgressBar();
|
|
74
|
-
}
|
|
70
|
+
this.updateProgressBar(i, this.data[i]);
|
|
75
71
|
}
|
|
76
72
|
|
|
77
73
|
if (this.data.length < this.progressBars.length) {
|
|
@@ -80,7 +76,15 @@ class Sandboxes extends Box {
|
|
|
80
76
|
}
|
|
81
77
|
}
|
|
82
78
|
|
|
83
|
-
this.setLabel(`${this.options.label} (${this.
|
|
79
|
+
this.setLabel(`${this.options.label} (${this.progressBars.length})`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Deletes last progress bar
|
|
83
|
+
deleteProgressBar() {
|
|
84
|
+
let i = this.progressBars.length - 1;
|
|
85
|
+
this.progressBars[i].label.destroy()
|
|
86
|
+
this.progressBars[i].progressBar.destroy()
|
|
87
|
+
this.progressBars.pop(i)
|
|
84
88
|
}
|
|
85
89
|
}
|
|
86
90
|
|