dcp-worker 3.3.12-0 → 3.3.12
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/bin/dcp-worker +118 -51
- package/lib/blessed-components/log.js +9 -6
- package/lib/dashboard-tui.js +24 -6
- package/lib/startWorkerLogger.js +10 -2
- package/lib/webgpu-info.js +8 -4
- package/lib/worker-loggers/console.js +44 -6
- package/lib/worker-loggers/dashboard.js +29 -6
- package/package.json +10 -10
package/bin/dcp-worker
CHANGED
|
@@ -23,9 +23,11 @@ const chalk = require('chalk');
|
|
|
23
23
|
const telnetd = require('../lib/remote-console');
|
|
24
24
|
|
|
25
25
|
const { slicesFetched, debugging, displayMaxDiagInfo } = require('../lib/utils');
|
|
26
|
+
const { a$sleep } = require('dcp/utils');
|
|
26
27
|
|
|
27
28
|
const configName = process.env.DCP_CONFIG || '../etc/dcp-worker-config';
|
|
28
29
|
const EXIT_UNHANDLED = 5;
|
|
30
|
+
const systemStateInfo = globalThis.systemStateInfo = {};
|
|
29
31
|
|
|
30
32
|
/* Setup the telnet REPL up early to ensure early-failure log messages are captured */
|
|
31
33
|
const replHelpers = {
|
|
@@ -44,6 +46,26 @@ const replHelpers = {
|
|
|
44
46
|
};
|
|
45
47
|
telnetd.init(replHelpers);
|
|
46
48
|
|
|
49
|
+
/**
|
|
50
|
+
* regexps of GPUs we cannot use. Properties match device descriptors. More regexps can be added via
|
|
51
|
+
* dcpConfig.bannedGPUs.
|
|
52
|
+
*/
|
|
53
|
+
const bannedGPUs =
|
|
54
|
+
{
|
|
55
|
+
device: /llvmpipe/,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Output startup banner message. Currently a wrapper for console.log, future plans are to make it
|
|
60
|
+
* possible to suppress these messages, and also to send them multiple places (eg tty and syslog)
|
|
61
|
+
*/
|
|
62
|
+
function bannerLog()
|
|
63
|
+
{
|
|
64
|
+
console.log.apply(console, arguments);
|
|
65
|
+
bannerLog.cumulative.push(arguments);
|
|
66
|
+
}
|
|
67
|
+
bannerLog.cumulative = [];
|
|
68
|
+
|
|
47
69
|
/* Initialize dcp-client with local config defaults and run the main function. DCP_CONFIG_COOKIE becomes dcpConfig.cookie.
|
|
48
70
|
* And dcpConfig is defined as a side effect of initializing dcp-client.
|
|
49
71
|
*/
|
|
@@ -138,13 +160,13 @@ function parseCliArgs()
|
|
|
138
160
|
leavePublicGroup: {
|
|
139
161
|
type: 'boolean',
|
|
140
162
|
hidden: true,
|
|
141
|
-
describe: 'Do not fetch slices from
|
|
163
|
+
describe: 'Do not fetch slices from global compute group.',
|
|
142
164
|
default: undefined,
|
|
143
165
|
},
|
|
144
166
|
|
|
145
167
|
publicGroupFallback: {
|
|
146
168
|
hidden: true,
|
|
147
|
-
describe: 'If set, worker will prefer private groups but fall back on the
|
|
169
|
+
describe: 'If set, worker will prefer private groups but fall back on the global group if no preferred work is available',
|
|
148
170
|
type: 'boolean',
|
|
149
171
|
default: undefined,
|
|
150
172
|
defaultDescription: undefined,
|
|
@@ -298,11 +320,11 @@ async function main()
|
|
|
298
320
|
require('../lib/startWorkerLogger').init(cliArgs); /* Start remote logger as early as possible */
|
|
299
321
|
verifyDefaultConfigIntegrity(); /* Bail before TUI & as early as possible if bad conf */
|
|
300
322
|
|
|
301
|
-
process.on('SIGINT',
|
|
323
|
+
process.on('SIGINT', handleSigDeath);
|
|
302
324
|
process.on('SIGTERM', handleSigDeath);
|
|
303
325
|
process.on('SIGQUIT', handleSigDeath);
|
|
304
326
|
process.on('unhandledRejection', handleUnhandled);
|
|
305
|
-
process.on('uncaughtException',
|
|
327
|
+
process.on('uncaughtException', handleUnhandled);
|
|
306
328
|
|
|
307
329
|
const getOpts = {};
|
|
308
330
|
if (cliArgs.defaultPaymentAddressToDCP)
|
|
@@ -405,14 +427,33 @@ async function main()
|
|
|
405
427
|
if (cliArgs.watchdogInterval)
|
|
406
428
|
dcpWorkerOptions.watchdogInterval = cliArgs.watchdogInterval;
|
|
407
429
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
430
|
+
if (dcpConfig.bannedGPUs)
|
|
431
|
+
{
|
|
432
|
+
for (let prop of dcpConfig.bannedGPUs)
|
|
433
|
+
{
|
|
434
|
+
if (!bannedGPUs[prop])
|
|
435
|
+
bannedGPUs[prop] = dcpConfig.bannedGPUs[prop];
|
|
436
|
+
else
|
|
437
|
+
bannedGPUs[prop] = new RegExp(`(${dcpConfig.bannedGPUs[prop].source})|(${bannedGPUs[prop].source})`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const nascentWorker = new DCPWorker(identityKeystore, dcpWorkerOptions);
|
|
442
|
+
bannerLog(` * Starting DCP Worker ${nascentWorker.workerId}`);
|
|
443
|
+
bannerLog(` . Using evaluator at ${dcpConfig.evaluator.location}`);
|
|
444
|
+
bannerLog(` . Configured for scheduler ${dcpConfig.scheduler.location}`);
|
|
445
|
+
bannerLog(` . Bank is ${dcpConfig.bank.location}`);
|
|
446
|
+
bannerLog(` . Earned funds will be deposited in account ${nascentWorker.paymentAddress}`);
|
|
447
|
+
bannerLog(` . Identity is ${nascentWorker.identityKeystore.address}`);
|
|
448
|
+
|
|
449
|
+
nascentWorker.on('warning', (...payload) => console.warn (...payload));
|
|
450
|
+
nascentWorker.on('stop', () => { console.log('Worker is stopping') });
|
|
451
|
+
nascentWorker.on('end', () => { logClosing('log', 'Worker has stopped') });
|
|
452
|
+
|
|
413
453
|
// Display clean diagnostic when not debugging and env var
|
|
414
454
|
// DCP_SUPERVISOR_DEBUG_DISPLAY_MAX_INFO isn't set.
|
|
415
|
-
|
|
455
|
+
nascentWorker.on('error', (error) => {
|
|
456
|
+
|
|
416
457
|
if (displayMaxDiagInfo())
|
|
417
458
|
console.error(error);
|
|
418
459
|
else
|
|
@@ -424,29 +465,29 @@ async function main()
|
|
|
424
465
|
console.error(`Error: ${error.message}`);
|
|
425
466
|
}
|
|
426
467
|
});
|
|
427
|
-
require('../lib/default-ui-events').hook(
|
|
468
|
+
require('../lib/default-ui-events').hook(nascentWorker, cliArgs);
|
|
428
469
|
|
|
429
470
|
if (cliArgs.outputMode === 'dashboard')
|
|
430
|
-
require('../lib/dashboard-tui').init(
|
|
471
|
+
require('../lib/dashboard-tui').init(nascentWorker, cliArgs, bannerLog.cumulative);
|
|
431
472
|
|
|
432
473
|
/* Let incorrect event-loop references keep us alive when linked with a debug library, but
|
|
433
474
|
* exit quickly/accurately for production code even when the library isn't perfect.
|
|
434
475
|
*/
|
|
435
476
|
if (require('dcp/build').config.build !== 'debug')
|
|
436
|
-
|
|
477
|
+
nascentWorker.on('end', processExit);
|
|
437
478
|
else
|
|
438
|
-
|
|
479
|
+
nascentWorker.on('end', () => setTimeout(processExit, getCleanupTimeoutMs()).unref());
|
|
439
480
|
|
|
440
481
|
if (dcpWorkerOptions.publicGroupFallback)
|
|
441
482
|
{
|
|
442
483
|
if (dcpWorkerOptions.leavePublicGroup)
|
|
443
|
-
console.warn(' !
|
|
484
|
+
console.warn(' ! Global Group fallback has been requested, but the global group is blocked by local configuration');
|
|
444
485
|
else
|
|
445
486
|
{
|
|
446
|
-
/* Enable
|
|
487
|
+
/* Enable global group fallback - this currently works by enabling or disabling the global group
|
|
447
488
|
* on the next fetch based on whether or not the most recent fetch was an empty task or not.
|
|
448
489
|
*/
|
|
449
|
-
|
|
490
|
+
nascentWorker.on('fetch', fetchEventHandler);
|
|
450
491
|
|
|
451
492
|
function fetchEventHandler(ev)
|
|
452
493
|
{
|
|
@@ -458,14 +499,8 @@ async function main()
|
|
|
458
499
|
}
|
|
459
500
|
}
|
|
460
501
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
introBanner += ` . Configured for scheduler ${dcpConfig.scheduler.location}` + '\n';
|
|
464
|
-
introBanner += ` . Bank is ${dcpConfig.bank.location}` + '\n';
|
|
465
|
-
introBanner += ` . Earned funds will be deposited in account ${worker.paymentAddress}` + '\n';
|
|
466
|
-
introBanner += ` . Identity is ${worker.identityKeystore.address}` + '\n';
|
|
467
|
-
|
|
468
|
-
function qty(amount, singular, plural) /* XXX i18n */
|
|
502
|
+
/** @todo i18n */
|
|
503
|
+
function qty(amount, singular, plural)
|
|
469
504
|
{
|
|
470
505
|
if (Array.isArray(amount))
|
|
471
506
|
amount = amount.length;
|
|
@@ -479,49 +514,70 @@ async function main()
|
|
|
479
514
|
}
|
|
480
515
|
|
|
481
516
|
if (dcpWorkerOptions.jobAddresses?.length > 0)
|
|
482
|
-
|
|
517
|
+
bannerLog(` * Processing only ${qty(dcpWorkerOptions.jobAddresses, 'job')} ` + dcpWorkerOptions.jobAddresses.join(', '));
|
|
483
518
|
if (dcpWorkerOptions.computeGroups && Object.keys(dcpWorkerOptions.computeGroups).length > 0)
|
|
484
|
-
|
|
519
|
+
bannerLog(` . Joining compute ${qty(dcpWorkerOptions.computeGroups, 'group')} ` + dcpWorkerOptions.computeGroups.map(el => el.joinKey).join(', '));
|
|
485
520
|
if (dcpWorkerOptions.publicGroupFallback)
|
|
486
|
-
|
|
521
|
+
bannerLog(' . Falling back on global group when preferred groups have no work');
|
|
487
522
|
if (dcpWorkerOptions.leavePublicGroup)
|
|
488
|
-
|
|
523
|
+
bannerLog(' . Leaving the global compute group');
|
|
489
524
|
if (dcpWorkerOptions.cores)
|
|
490
|
-
|
|
525
|
+
bannerLog(` . Configured Cores: ${dcpWorkerOptions.cores.cpu},${dcpWorkerOptions.cores.gpu}`);
|
|
491
526
|
if (typeof dcpWorkerOptions.maxSandboxes !== 'undefined')
|
|
492
|
-
|
|
527
|
+
bannerLog(` . Maximum Sandboxes: ${dcpWorkerOptions.maxSandboxes}`);
|
|
493
528
|
if (cliArgs.verbose)
|
|
494
|
-
|
|
529
|
+
bannerLog(` + Verbosity level: ${cliArgs.verbose}`);
|
|
495
530
|
if (telnetd.hasOwnProperty('port'))
|
|
496
|
-
|
|
531
|
+
bannerLog(` ! telnetd listening on port ${telnetd.port}`);
|
|
497
532
|
|
|
498
533
|
const { worktimes } = require('dcp-client/libexec/sandbox/worktimes');
|
|
499
534
|
if (Object.keys(worktimes).length > 0)
|
|
500
535
|
{
|
|
501
|
-
|
|
536
|
+
bannerLog(' . Worktimes Available:');
|
|
502
537
|
for (const wt of worktimes)
|
|
503
|
-
|
|
538
|
+
bannerLog(` -\t${wt.name}@${wt.versions.join(';')}`);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
let webgpuInfo;
|
|
542
|
+
console.throb('log', ' ! Waiting for dcp-evaluator to start...');
|
|
543
|
+
for (let i=0; !webgpuInfo; i++)
|
|
544
|
+
{
|
|
545
|
+
webgpuInfo = await require('../lib/webgpu-info').checkWebGPU();
|
|
546
|
+
if (webgpuInfo)
|
|
547
|
+
break;
|
|
548
|
+
console.throb();
|
|
549
|
+
await a$sleep(Math.max(i + 1, 10) / 4);
|
|
550
|
+
console.throb();
|
|
504
551
|
}
|
|
505
552
|
|
|
506
|
-
const webgpuInfo = await require('../lib/webgpu-info').checkWebGPU();
|
|
507
553
|
if (!webgpuInfo)
|
|
508
|
-
|
|
554
|
+
bannerLog(' . WebGPU detection failed');
|
|
509
555
|
else if (!webgpuInfo.enabled)
|
|
510
|
-
|
|
556
|
+
{
|
|
557
|
+
bannerLog(' . WebGPU not enabled');
|
|
558
|
+
systemStateInfo.gpu = false;
|
|
559
|
+
}
|
|
511
560
|
else
|
|
512
561
|
{
|
|
513
|
-
|
|
562
|
+
bannerLog(' . WebGPU available. GPU info:');
|
|
514
563
|
for (let descriptor in webgpuInfo.info)
|
|
515
|
-
|
|
516
|
-
|
|
564
|
+
bannerLog(` -\t${descriptor}: ${webgpuInfo.info[descriptor]}`);
|
|
565
|
+
systemStateInfo.gpu = Object.assign({}, webgpuInfo.info);
|
|
566
|
+
systemStateInfo.gpu.device
|
|
567
|
+
for (let descriptor in bannedGPUs)
|
|
568
|
+
{
|
|
569
|
+
if (bannedGPUs[descriptor].test(webgpuInfo.info[descriptor]))
|
|
570
|
+
{
|
|
571
|
+
console.error(' * This GPU is not supported; disabling');
|
|
572
|
+
dcpWorkerOptions.cores = { cpu: dcpWorkerOptions.cores.cpu, gpu: 0 };
|
|
573
|
+
systemStateInfo.gpu.disabled = true;
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
517
577
|
}
|
|
518
578
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
introBanner += ' * Ready' + '\n';
|
|
522
|
-
|
|
523
|
-
console.log(introBanner);
|
|
524
|
-
require('../lib/check-scheduler-version').check();
|
|
579
|
+
bannerLog(' . Supervisor version: ' + nascentWorker.supervisorVersion);
|
|
580
|
+
bannerLog(' . Output mode: ' + cliArgs.outputMode);
|
|
525
581
|
|
|
526
582
|
if (parseFloat(cliArgs.reportInterval))
|
|
527
583
|
{
|
|
@@ -531,8 +587,15 @@ async function main()
|
|
|
531
587
|
console.warn('Ignoring --reportInterval in dashboard output mode');
|
|
532
588
|
}
|
|
533
589
|
|
|
534
|
-
/* Start the worker. Normal process exit happens by virtue of the worker<end> event
|
|
535
|
-
|
|
590
|
+
/* Start the worker. Normal process exit happens by virtue of the worker<end> event. Move forward one
|
|
591
|
+
* tick in case processExit was called during initialization.
|
|
592
|
+
*/
|
|
593
|
+
setImmediate(async function workerStart() {
|
|
594
|
+
bannerLog(' * Ready.\n');
|
|
595
|
+
require('../lib/check-scheduler-version').check();
|
|
596
|
+
worker = nascentWorker;
|
|
597
|
+
await worker.start();
|
|
598
|
+
});
|
|
536
599
|
}
|
|
537
600
|
|
|
538
601
|
/**
|
|
@@ -747,21 +810,25 @@ function handleSigDeath(signalName, signal)
|
|
|
747
810
|
}
|
|
748
811
|
|
|
749
812
|
if (!worker)
|
|
813
|
+
{
|
|
750
814
|
console.warn(`trapped ${signalName}, signal ${signal}`);
|
|
815
|
+
die();
|
|
816
|
+
}
|
|
751
817
|
else
|
|
752
818
|
{
|
|
753
819
|
const immediate = signalName === 'SIGQUIT' || handleSigDeath.count > 1;
|
|
754
820
|
console.warn(`trapped ${signalName}, signal ${signal} -- stopping worker`,
|
|
755
821
|
immediate ? 'immediately' : `after ${handleSigDeath.count} slices have finished`);
|
|
756
822
|
worker.stop(immediate);
|
|
823
|
+
setTimeout(die, getCleanupTimeoutMs()).unref();
|
|
757
824
|
}
|
|
825
|
+
process.emit('dcpBeforeExit');
|
|
758
826
|
|
|
759
827
|
function die()
|
|
760
828
|
{
|
|
761
829
|
processExit(signal - 128);
|
|
762
830
|
}
|
|
763
831
|
|
|
764
|
-
setTimeout(die, getCleanupTimeoutMs()).unref();
|
|
765
832
|
if (handleSigDeath.count === 3)
|
|
766
833
|
die();
|
|
767
834
|
}
|
|
@@ -818,7 +885,7 @@ function verifyDefaultConfigIntegrity()
|
|
|
818
885
|
if (!originalMd5sum.startsWith(actualMd5sum))
|
|
819
886
|
{
|
|
820
887
|
console.warn(chalk.yellow(` ! Detected modified ${workerConfPath};`));
|
|
821
|
-
console.warn('
|
|
888
|
+
console.warn(' ! DCP Worker configuration changes should not be made by updating the default');
|
|
822
889
|
console.warn(' config, as that file will be overwritten on the next npm update. Instead,');
|
|
823
890
|
console.warn(' make changes via one of the following locations:');
|
|
824
891
|
console.warn(' - ~/.dcp/dcp-worker/dcp-config.js');
|
|
@@ -40,19 +40,22 @@ class Log extends Box
|
|
|
40
40
|
|
|
41
41
|
log(...args)
|
|
42
42
|
{
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
'');
|
|
46
|
-
|
|
47
|
-
this.logLines.push(str);
|
|
43
|
+
args = args.map(arg =>`${typeof arg === 'string'? arg : JSON.stringify(arg, null, 2)}`);
|
|
44
|
+
this.logLines.push(args.join(' '));
|
|
48
45
|
|
|
49
46
|
if (this.logLines.length > this.options.bufferLength)
|
|
50
47
|
this.logLines.shift();
|
|
51
48
|
|
|
52
|
-
this.
|
|
49
|
+
this.lastLogContent = this.logLines.join('\n');
|
|
50
|
+
this.setContent(this.lastLogContent);
|
|
53
51
|
if (!this.paused)
|
|
54
52
|
this.setScrollPerc(100);
|
|
55
53
|
}
|
|
54
|
+
|
|
55
|
+
advanceThrob(char)
|
|
56
|
+
{
|
|
57
|
+
this.setContent(this.lastLogContent + char);
|
|
58
|
+
}
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
Object.assign(exports, {
|
package/lib/dashboard-tui.js
CHANGED
|
@@ -18,6 +18,7 @@ const components = require('./blessed-components');
|
|
|
18
18
|
const utils = require('../lib/utils');
|
|
19
19
|
|
|
20
20
|
const { replaceWorkerEventHandler, replaceSandboxEventHandler, newSandboxCallbacks } = require('./default-ui-events');
|
|
21
|
+
const systemStateInfo = globalThis.systemStateInfo;
|
|
21
22
|
|
|
22
23
|
const SLICE_FETCH_STATUS = {
|
|
23
24
|
IDLE: chalk.yellow('Idle'),
|
|
@@ -36,7 +37,7 @@ const screenConf = {
|
|
|
36
37
|
* @param {Worker} worker Reference to the DCP Worker
|
|
37
38
|
* @param {object} options Options which may affect behaviour. Not currently used.
|
|
38
39
|
*/
|
|
39
|
-
exports.init = function dashboard$$init(worker, options)
|
|
40
|
+
exports.init = function dashboard$$init(worker, options, bannerLogCumulative)
|
|
40
41
|
{
|
|
41
42
|
var sliceFetchStatus = SLICE_FETCH_STATUS.IDLE;
|
|
42
43
|
var totalDCCs = 0;
|
|
@@ -51,12 +52,12 @@ exports.init = function dashboard$$init(worker, options)
|
|
|
51
52
|
screen.destroy();
|
|
52
53
|
});
|
|
53
54
|
|
|
54
|
-
const grid = new contrib.grid({ rows: 3, cols:
|
|
55
|
-
const workerInfoPane = grid.set(2, 0, 1,
|
|
55
|
+
const grid = new contrib.grid({ rows: 3, cols: 6, screen }); // eslint-disable-line new-cap
|
|
56
|
+
const workerInfoPane = grid.set(2, 0, 1, 6, components.log, {
|
|
56
57
|
label: 'Worker Status',
|
|
57
58
|
scrollbar: { bg: 'blue' },
|
|
58
59
|
});
|
|
59
|
-
const logPane = grid.set(0, 2, 2,
|
|
60
|
+
const logPane = grid.set(0, 2, 2, 4, components.log, {
|
|
60
61
|
label: 'Worker Log',
|
|
61
62
|
scrollbar: { bg: 'blue' },
|
|
62
63
|
});
|
|
@@ -115,9 +116,11 @@ exports.init = function dashboard$$init(worker, options)
|
|
|
115
116
|
};
|
|
116
117
|
|
|
117
118
|
delete exports.init; /* singleton */
|
|
118
|
-
|
|
119
|
+
console.log(' . Starting dashboard and redirecting logs');
|
|
119
120
|
if (!usingDebugger)
|
|
120
121
|
exports.logPane = logPane; /* now dashboard log can find the pane */
|
|
122
|
+
for (let args of bannerLogCumulative) /* re-draw previously-emited log lines as screen has cleared */
|
|
123
|
+
logPane.log(...args);
|
|
121
124
|
setInterval(() => screen.render(), 2000).unref(); /* ensure we didn't forget to render an important update */
|
|
122
125
|
updateWorkerInfo();
|
|
123
126
|
|
|
@@ -130,10 +133,25 @@ exports.init = function dashboard$$init(worker, options)
|
|
|
130
133
|
setInterval(updateWorkerInfo, 1000).unref();
|
|
131
134
|
function updateWorkerInfo(fetchInfo)
|
|
132
135
|
{
|
|
136
|
+
var gpuInfo = '';
|
|
133
137
|
const workerOptions = worker.workerOptions;
|
|
134
138
|
if (fetchInfo)
|
|
135
139
|
lastTask = fetchInfo;
|
|
136
140
|
|
|
141
|
+
if (typeof systemStateInfo.gpu === 'undefined')
|
|
142
|
+
gpuInfo = '';
|
|
143
|
+
else if (systemStateInfo.gpu === false)
|
|
144
|
+
gpuInfo = 'none';
|
|
145
|
+
else if (typeof systemStateInfo.gpu === 'object')
|
|
146
|
+
{
|
|
147
|
+
if (systemStateInfo.gpu.disabled)
|
|
148
|
+
gpuInfo = chalk.red('disabled') + chalk.grey(` (${systemStateInfo.gpu.device})`);
|
|
149
|
+
else
|
|
150
|
+
gpuInfo = chalk.cyan(systemStateInfo.gpu.device);
|
|
151
|
+
}
|
|
152
|
+
else
|
|
153
|
+
gpuInfo = chalk.red(`error detecting`);
|
|
154
|
+
|
|
137
155
|
workerInfoPane.setLabel(`Worker Status [${sliceFetchStatus}]`);
|
|
138
156
|
workerInfoPane.setContent([
|
|
139
157
|
chalk.green(` DCCs Earned: ${chalk.bold(totalDCCs.toFixed(3))} ⊇`),
|
|
@@ -142,7 +160,7 @@ exports.init = function dashboard$$init(worker, options)
|
|
|
142
160
|
` Bank: ${chalk.yellow(dcpConfig.bank.location.href)}`,
|
|
143
161
|
` Bank Account: ${chalk.yellow(worker.paymentAddress || 'Starting...')}`,
|
|
144
162
|
` Identity: ${chalk.yellow(worker.identityKeystore? worker.identityKeystore.address : 'Starting...')}`,
|
|
145
|
-
`
|
|
163
|
+
` GPU: ${gpuInfo}`,
|
|
146
164
|
` Jobs: ${workerOptions.jobAddresses?.length ? workerOptions.jobAddresses.join(', ') : '<any>'}`,
|
|
147
165
|
` Compute Groups: ${Object.keys(workerOptions.computeGroups).length + (workerOptions.leavePublicGroup ? 0 : 1)}`,
|
|
148
166
|
`Global Compute Group: ${workerOptions.leavePublicGroup ? 'no' : 'yes'}`,
|
package/lib/startWorkerLogger.js
CHANGED
|
@@ -50,7 +50,7 @@ function getLogger(options)
|
|
|
50
50
|
* merely a passthrough shim, this is a "dead end" interceptor - we do not pass the log message through
|
|
51
51
|
* to the original console method. This implies, for example, that sending console messages to syslogd
|
|
52
52
|
* quiesces the tty output.
|
|
53
|
-
*
|
|
53
|
+
*
|
|
54
54
|
* @param {object} options - cliArgs from worker
|
|
55
55
|
*/
|
|
56
56
|
exports.init = function startWorkerLogger$$init(options)
|
|
@@ -92,8 +92,16 @@ exports.init = function startWorkerLogger$$init(options)
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
if (logger.throb)
|
|
96
|
+
console.throb = logger.throb;
|
|
97
|
+
else
|
|
98
|
+
console.throb = function throwFallback(facility, ...args) {
|
|
99
|
+
if (facility && facility !== 'throb')
|
|
100
|
+
console[facility](...args);
|
|
101
|
+
};
|
|
102
|
+
|
|
95
103
|
require('./remote-console').reintercept();
|
|
96
|
-
}
|
|
104
|
+
}
|
|
97
105
|
|
|
98
106
|
/**
|
|
99
107
|
* Format console.log arguments for use by a non-native logger, eg syslog. All non-string arguments are
|
package/lib/webgpu-info.js
CHANGED
|
@@ -13,6 +13,9 @@ const evaluatorId = 'webgpuCheck';
|
|
|
13
13
|
|
|
14
14
|
async function eval$$webgpu()
|
|
15
15
|
{
|
|
16
|
+
if (typeof initWebGPU === 'function')
|
|
17
|
+
await initWebGPU();
|
|
18
|
+
|
|
16
19
|
if (!(typeof globalThis.navigator?.gpu === 'object'))
|
|
17
20
|
return { enabled: false };
|
|
18
21
|
|
|
@@ -67,15 +70,16 @@ function checkEvaluatorWebGPU(evaluatorConfig)
|
|
|
67
70
|
noResponse.intr();
|
|
68
71
|
});
|
|
69
72
|
|
|
70
|
-
noResponse = a$sleep(
|
|
71
|
-
noResponse.then(
|
|
72
|
-
process.
|
|
73
|
+
noResponse = a$sleep(2);
|
|
74
|
+
noResponse.then(resolve); /* no answer */
|
|
75
|
+
noResponse.finally(() => process.off('dcpBeforeExit', noResponse.intr));
|
|
76
|
+
process.on('dcpBeforeExit', noResponse.intr);
|
|
73
77
|
|
|
74
78
|
evaluatorHandle.onmessage = function onmessage(event)
|
|
75
79
|
{
|
|
76
80
|
const reply = kvin.unmarshal(event.data).value;
|
|
77
81
|
if (reply.request === `evalResult::${evaluatorId}`)
|
|
78
|
-
resolve(reply.data);
|
|
82
|
+
resolve(reply.data /* { enabled: false|true } */);
|
|
79
83
|
}
|
|
80
84
|
|
|
81
85
|
const message = {
|
|
@@ -16,6 +16,9 @@ const process = require('process');
|
|
|
16
16
|
exports.init = function console$$init(options)
|
|
17
17
|
{
|
|
18
18
|
const myConsole = new (require('console').Console)(process);
|
|
19
|
+
var lastWasThrobber = false;
|
|
20
|
+
var i = 0;
|
|
21
|
+
var throbArgsCache = false;
|
|
19
22
|
|
|
20
23
|
delete exports.init; // singleton
|
|
21
24
|
if (process.env.RAW_CONSOLE)
|
|
@@ -24,12 +27,47 @@ exports.init = function console$$init(options)
|
|
|
24
27
|
exports.raw = function console$$raw(level, ...args) {
|
|
25
28
|
myConsole[level](...args);
|
|
26
29
|
};
|
|
30
|
+
return;
|
|
27
31
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
|
|
33
|
+
/* Log a single string to the console; conceptually very similar to other loggers */
|
|
34
|
+
exports.at = function console$$at(level, ...args) {
|
|
35
|
+
if (lastWasThrobber)
|
|
36
|
+
{
|
|
37
|
+
args.unshift(' \n');
|
|
38
|
+
lastWasThrobber = false;
|
|
39
|
+
}
|
|
40
|
+
myConsole[level](args.join(' '));
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const throbChars = '/-\\|';
|
|
44
|
+
/**
|
|
45
|
+
* throb API: calls with arguments set facility and message. First call without argument emits the
|
|
46
|
+
* message. All calls without arguments advance the throbber.
|
|
47
|
+
*/
|
|
48
|
+
exports.throb = function throb(throbFacility, ...args) {
|
|
49
|
+
if (throbFacility)
|
|
50
|
+
{
|
|
51
|
+
throbArgsCache = { throbFacility, args };
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const stream = throbFacility === 'error' || throbFacility === 'warn' ? process.stderr : process.stdout;
|
|
56
|
+
|
|
57
|
+
if (throbArgsCache)
|
|
58
|
+
{
|
|
59
|
+
if (stream.isTTY)
|
|
60
|
+
stream.write(throbArgsCache.args.join(' '));
|
|
61
|
+
else
|
|
62
|
+
console[throbArgsCache.throbFacility](...throbArgsCache.args);
|
|
63
|
+
throbArgsCache = false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (stream.isTTY)
|
|
67
|
+
{
|
|
68
|
+
i = (i + 1) % throbChars.length;
|
|
69
|
+
stream.write(throbChars[i] + '\u0008');
|
|
70
|
+
lastWasThrobber = true;
|
|
71
|
+
}
|
|
34
72
|
}
|
|
35
73
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @file worker-loggers/dashboard.js
|
|
3
3
|
* @author Ryan Rossiter, ryan@kingsds.network
|
|
4
4
|
* @date April 2020
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
6
|
* This worker logger uses the blessed library to create
|
|
7
7
|
* a monitoring dashboard for the worker.
|
|
8
8
|
*/
|
|
@@ -17,11 +17,13 @@ const chalk = require('chalk');
|
|
|
17
17
|
*/
|
|
18
18
|
exports.init = function dashboardLogger$$init(options)
|
|
19
19
|
{
|
|
20
|
+
const dashboardTui = require('../dashboard-tui');
|
|
21
|
+
const inspect = Symbol.for('nodejs.util.inspect.custom');
|
|
22
|
+
var throbPos = 0;
|
|
23
|
+
var throbArgsCache = false;
|
|
24
|
+
|
|
20
25
|
function logWrapperFactory(logLevel)
|
|
21
26
|
{
|
|
22
|
-
const inspect = Symbol.for('nodejs.util.inspect.custom');
|
|
23
|
-
const dashboardTui = require('../dashboard-tui');
|
|
24
|
-
|
|
25
27
|
return function wrappedLogFun() {
|
|
26
28
|
if (!dashboardTui.logPane) /* no logPane => TUI not ready - fallback to console */
|
|
27
29
|
{
|
|
@@ -33,7 +35,7 @@ exports.init = function dashboardLogger$$init(options)
|
|
|
33
35
|
logAt(logLevel, ...arguments);
|
|
34
36
|
return;
|
|
35
37
|
}
|
|
36
|
-
|
|
38
|
+
|
|
37
39
|
const argv = Array.from(arguments);
|
|
38
40
|
for (let i in argv)
|
|
39
41
|
{
|
|
@@ -48,5 +50,26 @@ exports.init = function dashboardLogger$$init(options)
|
|
|
48
50
|
|
|
49
51
|
for (let level of ['log', 'warn', 'debug', 'info', 'error'])
|
|
50
52
|
exports[level] = logWrapperFactory(level);
|
|
51
|
-
}
|
|
52
53
|
|
|
54
|
+
const throbChars = '/-\\|';
|
|
55
|
+
/**
|
|
56
|
+
* throb API: calls with arguments set facility and message. First call without argument emits the
|
|
57
|
+
* message. All calls without arguments advance the throbber.
|
|
58
|
+
*/
|
|
59
|
+
exports.throb = function throb(throbFacility, ...args) {
|
|
60
|
+
if (throbFacility)
|
|
61
|
+
{
|
|
62
|
+
throbArgsCache = { throbFacility, args };
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (throbArgsCache)
|
|
67
|
+
{
|
|
68
|
+
exports[throbArgsCache.throbFacility](...throbArgsCache.args);
|
|
69
|
+
throbArgsCache = false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
throbPos = (throbPos + 1) % throbChars.length;
|
|
73
|
+
dashboardTui.logPane.advanceThrob(throbChars[throbPos]);
|
|
74
|
+
}
|
|
75
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dcp-worker",
|
|
3
|
-
"version": "3.3.12
|
|
3
|
+
"version": "3.3.12",
|
|
4
4
|
"description": "Node.js Worker for Distributive Compute Platform",
|
|
5
5
|
"main": "bin/dcp-worker",
|
|
6
6
|
"keywords": [
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
},
|
|
13
13
|
"repository": {
|
|
14
14
|
"type": "git",
|
|
15
|
-
"url": "git
|
|
15
|
+
"url": "git@github.com:Distributed-Compute-Labs/dcp-worker.git"
|
|
16
16
|
},
|
|
17
17
|
"license": "MIT",
|
|
18
18
|
"author": "Distributive Corp.",
|
|
@@ -37,18 +37,18 @@
|
|
|
37
37
|
"prepublishOnly": "npm-hooks/prepublish"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"blessed": "
|
|
40
|
+
"blessed": "0.1.81",
|
|
41
41
|
"blessed-contrib": "4.11.0",
|
|
42
|
-
"chalk": "
|
|
43
|
-
"dcp-client": "4.4.11
|
|
44
|
-
"kvin": "
|
|
45
|
-
"posix-getopt": "
|
|
46
|
-
"semver": "
|
|
42
|
+
"chalk": "4.1.2",
|
|
43
|
+
"dcp-client": "4.4.11",
|
|
44
|
+
"kvin": "1.2.14",
|
|
45
|
+
"posix-getopt": "1.2.1",
|
|
46
|
+
"semver": "7.6.3",
|
|
47
47
|
"syslog-client": "1.1.1"
|
|
48
48
|
},
|
|
49
49
|
"optionalDependencies": {
|
|
50
|
-
"dbus-next": "
|
|
51
|
-
"telnet-console": "
|
|
50
|
+
"dbus-next": "0.10.2",
|
|
51
|
+
"telnet-console": "1.0.5"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@distributive/eslint-config": "2.1.4",
|