dcp-worker 4.5.0 → 4.5.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/.gitlab-ci.yml +1 -0
- package/bin/collect-debug-info +73 -30
- package/bin/dcp-evaluator-manager +46 -15
- package/bin/dcp-task-probe +2 -5
- package/bin/dcp-worker +105 -44
- package/lib/loggers.js +1 -1
- package/lib/p2p-shared.js +314 -0
- package/lib/pidfile.js +2 -2
- package/lib/utils.js +34 -14
- package/lib/worker-consoles/dashboard-console.js +9 -2
- package/lib/worker-loggers/event-log.js +3 -0
- package/lib/worker-loggers/logfile.js +2 -0
- package/lib/worker-loggers/p2p.js +197 -0
- package/lib/worker-loggers/syslog.js +2 -0
- package/package.json +9 -4
- package/tests/worker-with-options.simple +5 -1
- package/www/admin/register-worker.html +1 -0
package/.gitlab-ci.yml
CHANGED
|
@@ -17,6 +17,7 @@ default:
|
|
|
17
17
|
image: node:lts
|
|
18
18
|
before_script:
|
|
19
19
|
- npm add --global npm@latest
|
|
20
|
+
- npm config set allow-git=all
|
|
20
21
|
# Access private deps. e.g., `dcp-client` from GitLab.
|
|
21
22
|
- git config --global
|
|
22
23
|
url."${CI_SERVER_PROTOCOL}://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_HOST}:${CI_SERVER_PORT}".insteadOf
|
package/bin/collect-debug-info
CHANGED
|
@@ -26,45 +26,36 @@ process.stdout.write(`
|
|
|
26
26
|
*** This program collects information from your computer, and sends it to
|
|
27
27
|
*** Distributive and our analytics partners. This includes your local DCP
|
|
28
28
|
*** configuration, which might include sensitive information such as Compute
|
|
29
|
-
*** Group
|
|
29
|
+
*** Group information, or API keys.
|
|
30
30
|
|
|
31
31
|
`);
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
for (; argv.length; argv.shift())
|
|
34
34
|
{
|
|
35
|
-
if (argv[0] === '-f' || argv[0] === '--force')
|
|
36
|
-
{
|
|
37
|
-
argv.shift();
|
|
38
|
-
force = true;
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (argv[0] === '-s')
|
|
43
|
-
{
|
|
44
|
-
syslogUrl = argv[0];
|
|
45
|
-
argv.shift();
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
35
|
if (argv[0].startsWith('--syslog='))
|
|
50
|
-
{
|
|
51
36
|
syslogUrl = argv[0].slice(0);
|
|
52
|
-
|
|
37
|
+
else if (argv[0].startsWith('--dcp-'))
|
|
53
38
|
continue;
|
|
39
|
+
else if (argv[0] === '-f' || argv[0] === '--force')
|
|
40
|
+
force = true;
|
|
41
|
+
else if (argv[0] === '-s')
|
|
42
|
+
{
|
|
43
|
+
syslogUrl = argv[1];
|
|
44
|
+
shift();
|
|
54
45
|
}
|
|
55
|
-
|
|
56
|
-
|
|
46
|
+
else if (argv.length === 1)
|
|
47
|
+
email = argv[0];
|
|
48
|
+
else
|
|
49
|
+
throw new Error('invalid argument: ' + argv[0]);
|
|
57
50
|
}
|
|
58
51
|
|
|
59
52
|
if (force)
|
|
60
53
|
{
|
|
61
54
|
go();
|
|
62
|
-
email =
|
|
55
|
+
email = email || 'dcp+worker-debug-info@distributive.network';
|
|
63
56
|
}
|
|
64
57
|
else
|
|
65
58
|
{
|
|
66
|
-
email = argv[0];
|
|
67
|
-
|
|
68
59
|
const rl = readline.createInterface({
|
|
69
60
|
input: process.stdin,
|
|
70
61
|
output: process.stdout
|
|
@@ -100,8 +91,6 @@ async function emailReport(report)
|
|
|
100
91
|
{
|
|
101
92
|
const protocol = require('dcp/protocol');
|
|
102
93
|
const worker = require('dcp/worker');
|
|
103
|
-
|
|
104
|
-
const conn = new protocol.Connection(dcpConfig.scheduler.services.mailgw);
|
|
105
94
|
const message = {
|
|
106
95
|
from: `${os.userInfo().username}-${worker.DistributiveWorker.obtainWorkerId()}-worker-${os.hostname()}@distributive.network`,
|
|
107
96
|
fromName: 'collect-debug-info',
|
|
@@ -112,6 +101,15 @@ async function emailReport(report)
|
|
|
112
101
|
body: `<html><pre>${report}</pre></html>`
|
|
113
102
|
};
|
|
114
103
|
|
|
104
|
+
if (email === '-')
|
|
105
|
+
{
|
|
106
|
+
console.log(report);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const mailgw = dcpConfig.scheduler.services.mailgw;
|
|
111
|
+
console.log(` - sending email via ${mailgw.location}`);
|
|
112
|
+
const conn = new protocol.Connection(mailgw);
|
|
115
113
|
const response = await conn.request('sendmail', message);
|
|
116
114
|
conn.close();
|
|
117
115
|
console.log(' - sent report to', message.to);
|
|
@@ -126,7 +124,7 @@ async function cmd(prog, args)
|
|
|
126
124
|
argv.unshift(prog);
|
|
127
125
|
argv.unshift('/c');
|
|
128
126
|
const s = execFileSync('cmd', argv, { encoding: 'utf8' });
|
|
129
|
-
return `------ [ ${prog} ]
|
|
127
|
+
return `------ [ ${prog} ] ------\n${s}`;
|
|
130
128
|
}
|
|
131
129
|
|
|
132
130
|
async function sh(prog, args)
|
|
@@ -134,7 +132,7 @@ async function sh(prog, args)
|
|
|
134
132
|
const argv = args.slice();
|
|
135
133
|
console.log(' -', prog, argv.join(' '));
|
|
136
134
|
const s = execFileSync(prog, argv, { encoding: 'utf8', maxBuffer: 1e9 });
|
|
137
|
-
return `------ [ ${prog} ]
|
|
135
|
+
return `------ [ ${prog} ] ------\n${s}`;
|
|
138
136
|
}
|
|
139
137
|
|
|
140
138
|
async function go()
|
|
@@ -147,9 +145,29 @@ async function go()
|
|
|
147
145
|
worker: { logging: { syslog: {} } },
|
|
148
146
|
}
|
|
149
147
|
});
|
|
148
|
+
const { DcpURL } = require('dcp/dcp-url');
|
|
149
|
+
DcpURL.prototype.toJSON = function() { return { href: this.href } };
|
|
150
|
+
URL.prototype.toJSON = function() { return { href: this.href } };
|
|
151
|
+
const dcpConfigNoCreds = Object.assign({}, dcpConfig);
|
|
152
|
+
dcpConfigNoCreds.worker = Object.assign({}, dcpConfigNoCreds.worker);
|
|
153
|
+
delete dcpConfigNoCreds.worker.computeGroups;
|
|
154
|
+
|
|
155
|
+
for (let serviceGroup in dcpConfig)
|
|
156
|
+
{
|
|
157
|
+
if (dcpConfig[serviceGroup].location)
|
|
158
|
+
dcpConfig[serviceGroup].location = new URL(dcpConfig[serviceGroup].location);
|
|
159
|
+
if (dcpConfig[serviceGroup].services)
|
|
160
|
+
{
|
|
161
|
+
for (let service in dcpConfig[serviceGroup].services)
|
|
162
|
+
{
|
|
163
|
+
if (dcpConfig[serviceGroup].services[service].location)
|
|
164
|
+
dcpConfig[serviceGroup].services[service].location = new URL(dcpConfig[serviceGroup].services[service].location);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
150
168
|
|
|
151
169
|
console.log(' - host information');
|
|
152
|
-
var report = `------ [ ${new Date()} ]
|
|
170
|
+
var report = `------ [ ${new Date()} ] ------
|
|
153
171
|
os: ${os.version()}
|
|
154
172
|
platform: node ${process.version} ${os.platform()} ${os.release()} ${os.machine()} ${os.endianness()}
|
|
155
173
|
uptime: ${Math.floor(os.uptime() / 86400)} days ${Number(((os.uptime() / 86400) % 1) * 86400).toFixed(1)} seconds, load average: ${os.loadavg().join(', ')}
|
|
@@ -161,11 +179,12 @@ cpus: ${JSON.stringify(os.cpus, null, 2)}
|
|
|
161
179
|
network: ${JSON.stringify(os.networkInterfaces, null, 2)}
|
|
162
180
|
more versions: ${JSON.stringify(process.versions, null, 2)}
|
|
163
181
|
`;
|
|
164
|
-
|
|
182
|
+
console.log(' - worker information');
|
|
183
|
+
report += await createWorkerReport();
|
|
165
184
|
console.log(' - dcp information');
|
|
166
185
|
report +=
|
|
167
186
|
`
|
|
168
|
-
dcpConfig: ${JSON.stringify(
|
|
187
|
+
dcpConfig: ${JSON.stringify(dcpConfigNoCreds, null, 2)}
|
|
169
188
|
`;
|
|
170
189
|
|
|
171
190
|
if (os.platform() === 'win32')
|
|
@@ -190,3 +209,27 @@ dcpConfig: ${JSON.stringify(dcpConfig, null, 2)}
|
|
|
190
209
|
else if (syslogUrl)
|
|
191
210
|
syslogReport(report);
|
|
192
211
|
}
|
|
212
|
+
|
|
213
|
+
async function createWorkerReport()
|
|
214
|
+
{
|
|
215
|
+
const identity = require('dcp/identity');
|
|
216
|
+
const wallet = require('dcp/wallet');
|
|
217
|
+
const utils = require('../lib/utils');
|
|
218
|
+
const { DistributiveWorker } = require('dcp/worker');
|
|
219
|
+
const worker = new DistributiveWorker(Object.assign({
|
|
220
|
+
unmanaged: true
|
|
221
|
+
}, dcpConfig.worker), Function).unref();
|
|
222
|
+
identity.interactive = false;
|
|
223
|
+
const rootIdentity = await wallet.getId();//identity.get();
|
|
224
|
+
await identity.masquerade(DistributiveWorker.obtainWorkerId(), '$login');
|
|
225
|
+
await worker.configure();
|
|
226
|
+
|
|
227
|
+
return `
|
|
228
|
+
root identity: ${rootIdentity.address}
|
|
229
|
+
masquerade: ${identity.get().address}
|
|
230
|
+
worker id: ${worker.id}
|
|
231
|
+
earnings acct: ${worker.config.paymentAddress}
|
|
232
|
+
join keys: ${Object.values(worker.config.computeGroups).map(cg => cg.joinKey)}
|
|
233
|
+
worker config: ${JSON.stringify(Object.assign({}, worker.config, { computeGroups: 'HIDDEN' }), null, 2)}
|
|
234
|
+
`
|
|
235
|
+
}
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
*/
|
|
20
20
|
'use strict';
|
|
21
21
|
|
|
22
|
+
const net = require('mux-net').hook();
|
|
22
23
|
const os = require('os');
|
|
23
24
|
const fs = require('fs');
|
|
24
25
|
const path = require('path');
|
|
25
|
-
const net = require('net');
|
|
26
26
|
const dns = require('dns');
|
|
27
27
|
const debug = require('debug');
|
|
28
28
|
const pidfile = require('../lib/pidfile');
|
|
@@ -64,6 +64,10 @@ const daemonConfig = {
|
|
|
64
64
|
|
|
65
65
|
async function processExit(code)
|
|
66
66
|
{
|
|
67
|
+
if (processExit.p$exiting)
|
|
68
|
+
return processExit.p$exiting;
|
|
69
|
+
processExit.p$exiting = new Promise(()=>1); /* never resolves, other "thread" will exit program */
|
|
70
|
+
|
|
67
71
|
if (typeof code === 'undefined')
|
|
68
72
|
code = process.exitCode;
|
|
69
73
|
console.debug('Exit, code', code);
|
|
@@ -80,7 +84,7 @@ Released under the terms of the MIT License.
|
|
|
80
84
|
|
|
81
85
|
Usage: ${process.argv[0]} [-h | --help] [--prefix=<dir>] [--pts=<dir>]
|
|
82
86
|
[--disable-monitor=<session|screensaver|signal>] [-i <timeout>]
|
|
83
|
-
[-p port] [-H hostname]
|
|
87
|
+
[-p port] [-H hostname[,hostname...]]
|
|
84
88
|
[-a] [-l | --max-load=<number>] [-r | --rate=<number>] [-L]
|
|
85
89
|
[-s | --signal=[name or number][,<toggle|quick>]]
|
|
86
90
|
[-T | --loadavg-type=<short,medium,long,random>]
|
|
@@ -127,32 +131,56 @@ Environment:
|
|
|
127
131
|
*/
|
|
128
132
|
async function listenForConnections(config)
|
|
129
133
|
{
|
|
130
|
-
|
|
131
|
-
|
|
134
|
+
const server = net.createServer((socket) => handleConnection(socket, config));
|
|
135
|
+
const hostnames = config.net.hostnames || [ config.net.hostname ];
|
|
136
|
+
const hosts = [];
|
|
132
137
|
|
|
133
|
-
if (
|
|
134
|
-
|
|
138
|
+
if (!hostnames[0])
|
|
139
|
+
{
|
|
140
|
+
hosts[0] = '::1';
|
|
141
|
+
hosts[1] = '127.0.0.1';
|
|
142
|
+
}
|
|
135
143
|
else
|
|
136
|
-
|
|
144
|
+
{
|
|
145
|
+
for (let host of hostnames)
|
|
146
|
+
{
|
|
147
|
+
try
|
|
148
|
+
{
|
|
149
|
+
const hostaddrs = await dns.promises.lookup(host, { all: true, order: 'verbatim' });
|
|
150
|
+
for (let hostaddr of hostaddrs)
|
|
151
|
+
hosts.push(hostaddr.address);
|
|
152
|
+
}
|
|
153
|
+
catch(error)
|
|
154
|
+
{
|
|
155
|
+
if (error.code === 'EAI_AGAIN')
|
|
156
|
+
console.error(`hostname ${host} not found - check /etc/hosts or DNS configuration`);
|
|
157
|
+
else
|
|
158
|
+
console.error(`error ${error.code} resolving host ${host}:`, error.message);
|
|
159
|
+
await processExit(4);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
137
163
|
|
|
138
164
|
server.on('error', (error) => {
|
|
139
165
|
delete error.stack;
|
|
166
|
+
if (processExit.p$exiting)
|
|
167
|
+
return;
|
|
140
168
|
console.error(error);
|
|
141
169
|
processExit(2);
|
|
142
170
|
});
|
|
143
171
|
|
|
144
|
-
|
|
145
|
-
|
|
172
|
+
console.log('Evaluator command is', config.proc, config.argv);
|
|
173
|
+
server.listen({ hosts, port: config.net.port }, function daemonReady() {
|
|
174
|
+
// eslint-ignore-block no-invalid-this
|
|
175
|
+
console.log(`Listening for connections on ${config.net.hostname} (${this._connectionKey})`);
|
|
146
176
|
if (Number(config.net.port) === 0)
|
|
147
177
|
{
|
|
148
178
|
console.log('Using dynamic port', server.address().port);
|
|
149
179
|
// Send info by IPC, if the spawn is setup for that. Probably don't need to try/catch.
|
|
150
180
|
/* WHAT IS THIS FOR? /wg feb 2026 */
|
|
151
181
|
if (process.send)
|
|
152
|
-
try { process.send(server.address().port); } catch (e) {}
|
|
182
|
+
try { process.send(server.address().port); } catch (e) { e; 'dontcare'; }
|
|
153
183
|
}
|
|
154
|
-
|
|
155
|
-
console.log('Evaluator command is', config.proc, config.argv);
|
|
156
184
|
});
|
|
157
185
|
}
|
|
158
186
|
|
|
@@ -430,7 +458,7 @@ async function dbusScreenSaverMonitor()
|
|
|
430
458
|
{
|
|
431
459
|
const prettyName = chosen.split('.')[1];
|
|
432
460
|
console.error(`${prettyName} screensaver doesn't support activeness query, screensaver is not started, or user ${os.userInfo().username} doesn't have access to dbus\n ${error}`);
|
|
433
|
-
processExit(3);
|
|
461
|
+
await processExit(3);
|
|
434
462
|
}
|
|
435
463
|
}
|
|
436
464
|
|
|
@@ -654,7 +682,9 @@ async function main()
|
|
|
654
682
|
|
|
655
683
|
case 'H':
|
|
656
684
|
{
|
|
657
|
-
daemonConfig.net.hostname
|
|
685
|
+
delete daemonConfig.net.hostname;
|
|
686
|
+
daemonConfig.net.hostnames = optarg.split(/[, ]+/);
|
|
687
|
+
console.log(daemonConfig.net.hostnames);
|
|
658
688
|
break;
|
|
659
689
|
}
|
|
660
690
|
|
|
@@ -763,7 +793,8 @@ async function main()
|
|
|
763
793
|
}
|
|
764
794
|
|
|
765
795
|
/* Initialize dcp-client to use only local resources before launching the main function */
|
|
766
|
-
try
|
|
796
|
+
try
|
|
797
|
+
{
|
|
767
798
|
process.on('SIGHUP', () => processExit( 1 - 128));
|
|
768
799
|
process.on('SIGINT', () => processExit( 2 - 128));
|
|
769
800
|
process.on('SIGTERM', () => processExit(15 - 128));
|
package/bin/dcp-task-probe
CHANGED
|
@@ -641,7 +641,7 @@ async function main()
|
|
|
641
641
|
console.log('Worker Id: ', workerId);
|
|
642
642
|
console.log('Max Sandboxes: ', workerConfig.maxSandboxes);
|
|
643
643
|
console.log('Cores: ', Object.assign({}, workerConfig.cores));
|
|
644
|
-
console.log('Utilization: ', workerConfig.utilization);
|
|
644
|
+
console.log('Utilization: ', Object.assign({}, workerConfig.utilization));
|
|
645
645
|
console.log('DCP Address: ', String(identity.get().address));
|
|
646
646
|
|
|
647
647
|
if (!task)
|
|
@@ -705,7 +705,4 @@ async function main()
|
|
|
705
705
|
}
|
|
706
706
|
|
|
707
707
|
/* Initialize dcp-client to use only local resources before launching the main function */
|
|
708
|
-
require('dcp-client').init({
|
|
709
|
-
programName: 'dcp-worker',
|
|
710
|
-
parseArgv: false,
|
|
711
|
-
}).then(main);
|
|
708
|
+
require('dcp-client').init({ programName: 'dcp-worker' }).then(main);
|
package/bin/dcp-worker
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
'use strict';
|
|
15
15
|
var worker;
|
|
16
|
+
var workerStarted = false;
|
|
16
17
|
|
|
17
18
|
const process = require('process');
|
|
18
19
|
const fs = require('fs');
|
|
@@ -26,6 +27,7 @@ const reports = require('../lib/reports');
|
|
|
26
27
|
const utils = require('../lib/utils');
|
|
27
28
|
const loggers = require('../lib/loggers');
|
|
28
29
|
var wallet, a$sleep, DistributiveWorker; /* populate in main() */
|
|
30
|
+
var noStartWorker = false;
|
|
29
31
|
|
|
30
32
|
const { exitCodes,
|
|
31
33
|
logLevels } = require('../lib/consts');
|
|
@@ -81,6 +83,7 @@ Options:
|
|
|
81
83
|
-o, --output=mode Set the console mode: text|dashboard|none
|
|
82
84
|
-l, --logger=type Add an additional logger: syslog, logfile
|
|
83
85
|
(all platforms), event-log (win32)
|
|
86
|
+
--no-logger=type Remove a logger
|
|
84
87
|
--logfile=filename Change filename, implies --logger=logfile
|
|
85
88
|
--overwrite-logfile Overwrite log files instead of appending
|
|
86
89
|
--syslog=url|facility Change syslog target config, implies
|
|
@@ -257,6 +260,9 @@ function processCliOptsPhase1(argv, operatingMode)
|
|
|
257
260
|
case 'l':
|
|
258
261
|
loggingOptions.loggers.push(optarg);
|
|
259
262
|
break;
|
|
263
|
+
case 'no-logger':
|
|
264
|
+
loggingOptions.loggers = loggingOptions.loggers.filter(logger => logger !== optarg);
|
|
265
|
+
break;
|
|
260
266
|
case 'syslog':
|
|
261
267
|
loggingOptions.loggers.push('syslog');
|
|
262
268
|
loggingOptions.syslogUrl = utils.makeSyslogUrl(loggingOptions.syslogUrl, optarg);
|
|
@@ -311,9 +317,11 @@ function processCliOptsPhase1(argv, operatingMode)
|
|
|
311
317
|
break;
|
|
312
318
|
}
|
|
313
319
|
/* options below this point are processed in both phase 1 and phase 2 */
|
|
320
|
+
case 'reset':
|
|
314
321
|
case 'claim-earnings':
|
|
315
322
|
case 'register':
|
|
316
323
|
operatingMode.zeroTrust = true;
|
|
324
|
+
/* fallthrough */
|
|
317
325
|
case 'show':
|
|
318
326
|
operatingMode.consoleType = 'stdio';
|
|
319
327
|
/* fallthrough */
|
|
@@ -384,7 +392,6 @@ async function processCliOptsPhase2(argv, operatingMode, loggingOptions)
|
|
|
384
392
|
break;
|
|
385
393
|
case 'show':
|
|
386
394
|
operatingMode.show = optarg;
|
|
387
|
-
operatingMode.consoleType = 'stdio';
|
|
388
395
|
break;
|
|
389
396
|
case 'startup-delay':
|
|
390
397
|
await a$sleep(Number(optarg));
|
|
@@ -421,6 +428,7 @@ async function processCliOptsPhase2(argv, operatingMode, loggingOptions)
|
|
|
421
428
|
console.log('Registration failure:', error.message);
|
|
422
429
|
debug('dcp-worker:registration')(error);
|
|
423
430
|
}
|
|
431
|
+
worker.config.unmanaged = true;
|
|
424
432
|
await cleanupThenExit(exitCodes.normal);
|
|
425
433
|
break;
|
|
426
434
|
}
|
|
@@ -465,13 +473,14 @@ async function processCliOptsPhase2(argv, operatingMode, loggingOptions)
|
|
|
465
473
|
break;
|
|
466
474
|
default:
|
|
467
475
|
throw new Error(`unhandled option '${option}'`);
|
|
468
|
-
|
|
476
|
+
/**** hidden / undocumented options below ****/
|
|
469
477
|
case 'slice-report-interval':
|
|
470
478
|
loggingOptions.sliceReportInterval = Number(optarg);
|
|
471
479
|
break;
|
|
472
480
|
case 'reset': /* can lose unclaimed earnings */
|
|
473
481
|
DistributiveWorker.resetLocalStorage();
|
|
474
482
|
console.info('reset complete');
|
|
483
|
+
worker.config.unmanaged = true;
|
|
475
484
|
await cleanupThenExit(exitCodes.normal);
|
|
476
485
|
break;
|
|
477
486
|
}
|
|
@@ -519,7 +528,6 @@ async function mergeDbAppConfig(remainArgv, operatingMode, loggingOptions)
|
|
|
519
528
|
*/
|
|
520
529
|
async function main()
|
|
521
530
|
{
|
|
522
|
-
var workerIsStopping = false;
|
|
523
531
|
const identity = require('dcp/identity');
|
|
524
532
|
/* handle file-wide dcp-client imports */
|
|
525
533
|
wallet = require('dcp/wallet');
|
|
@@ -546,6 +554,8 @@ async function main()
|
|
|
546
554
|
loggingOptions, /* options to tell us where logs go besides the console */
|
|
547
555
|
} = processCliOptsPhase1(process.argv, operatingMode);
|
|
548
556
|
|
|
557
|
+
if (!operatingMode.zeroTrust)
|
|
558
|
+
loggingOptions.loggers.push('p2p');
|
|
549
559
|
if (dcpConfig.worker.logging?.syslog)
|
|
550
560
|
loggingOptions.loggers.push('syslog');
|
|
551
561
|
if (dcpConfig.worker.logging?.logfile)
|
|
@@ -582,7 +592,6 @@ async function main()
|
|
|
582
592
|
worker.runInfo.type = 'dcp-worker';
|
|
583
593
|
worker.on('warning', (...payload) => console.warn (...payload));
|
|
584
594
|
worker.on('claim', amount => console.log(` . transfered ${amount} ⊇ to ${worker.config.paymentAddress}`));
|
|
585
|
-
worker.on('stop', () => workerIsStopping = true );
|
|
586
595
|
await processCliOptsPhase2(remainArgv, operatingMode, loggingOptions);
|
|
587
596
|
|
|
588
597
|
if (operatingMode.show)
|
|
@@ -623,6 +632,7 @@ async function main()
|
|
|
623
632
|
|
|
624
633
|
require('../lib/default-ui-events').hook(worker, loggingOptions);
|
|
625
634
|
console.setWorker(worker);
|
|
635
|
+
require('../lib/p2p-shared').init(worker);
|
|
626
636
|
|
|
627
637
|
if (worker.config.jobIds?.length > 0)
|
|
628
638
|
console.info(` * Processing only ${utils.qty(worker.config.jobIds, 'job')} ` + worker.config.jobIds.join(', '));
|
|
@@ -635,29 +645,51 @@ async function main()
|
|
|
635
645
|
console.info(` + Verbosity level: ${loggingOptions.verbose}`);
|
|
636
646
|
|
|
637
647
|
/* Poll the evaluator forever until it accepts a connection */
|
|
638
|
-
let
|
|
648
|
+
let evaluatorInfo = false;
|
|
649
|
+
let p$throbSleep;
|
|
639
650
|
console.throb(` . Waiting for dcp-evaluator on ${utils.shortLoc(sandboxConfig.location)} to start...`);
|
|
640
|
-
|
|
651
|
+
function dieBeforeEvaluatorReady()
|
|
652
|
+
{
|
|
653
|
+
debug('dcp-worker:exit')('Trapped DistributiveWorker<stop> stop event before evaluator ready');
|
|
654
|
+
evaluatorInfo = null;
|
|
655
|
+
p$throbSleep?.intr();
|
|
656
|
+
}
|
|
657
|
+
worker.once('end', dieBeforeEvaluatorReady);
|
|
658
|
+
|
|
659
|
+
for (let i=0; evaluatorInfo === false; i++)
|
|
641
660
|
{
|
|
642
661
|
const ts = performance.now();
|
|
643
|
-
if ((
|
|
662
|
+
if ((evaluatorInfo = await require('../lib/worker-info').getEvaluatorInformation(sandboxConfig)))
|
|
644
663
|
break;
|
|
645
664
|
if (i === 0 && operatingMode.unmanaged !== true)
|
|
646
665
|
utils.noteWorkerStart(worker);
|
|
647
666
|
if (performance.now() - ts > 100)
|
|
648
667
|
console.throb();
|
|
649
|
-
|
|
668
|
+
p$throbSleep = a$sleep(Math.max(i + 1, 10) / 4);
|
|
669
|
+
await p$throbSleep;
|
|
650
670
|
console.throb();
|
|
651
671
|
}
|
|
672
|
+
worker.off('end', dieBeforeEvaluatorReady);
|
|
673
|
+
worker.once('end', () => {
|
|
674
|
+
debug('dcp-worker:exit')('Trapped DistributiveWorker<end>');
|
|
675
|
+
process.nextTick(() => cleanupThenExit(exitCodes.normal));
|
|
676
|
+
/* clean up at the end of tick so that other end event handlers can fire. */
|
|
677
|
+
});
|
|
652
678
|
|
|
653
|
-
if (
|
|
679
|
+
if (!evaluatorInfo)
|
|
680
|
+
{
|
|
681
|
+
console.warn(` . Could not contact dcp-evaluator on ${utils.shortLoc(sandboxConfig.location)} to start...`);
|
|
682
|
+
await cleanupThenExit(exitCodes.normal);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
if (Object.keys(evaluatorInfo.worktimes).length > 0)
|
|
654
686
|
{
|
|
655
687
|
console.info(' . Worktimes Available:');
|
|
656
|
-
for (const wt of
|
|
688
|
+
for (const wt of evaluatorInfo.worktimes)
|
|
657
689
|
console.info(` - ${wt.name}@${wt.version}`);
|
|
658
690
|
}
|
|
659
691
|
|
|
660
|
-
if (!
|
|
692
|
+
if (!evaluatorInfo.webgpu.enabled)
|
|
661
693
|
{
|
|
662
694
|
console.info(' . WebGPU not enabled');
|
|
663
695
|
systemStateInfo.gpu = false;
|
|
@@ -671,9 +703,9 @@ async function main()
|
|
|
671
703
|
else
|
|
672
704
|
{
|
|
673
705
|
console.info(' . WebGPU available. GPU info:');
|
|
674
|
-
for (let descriptor in
|
|
675
|
-
console.info(` - ${descriptor}: ${
|
|
676
|
-
systemStateInfo.gpu = Object.assign({},
|
|
706
|
+
for (let descriptor in evaluatorInfo.webgpu.info)
|
|
707
|
+
console.info(` - ${descriptor}: ${evaluatorInfo.webgpu.info[descriptor]}`);
|
|
708
|
+
systemStateInfo.gpu = Object.assign({}, evaluatorInfo.webgpu.info);
|
|
677
709
|
|
|
678
710
|
/** @todo move bannedGPU support into DistributiveWorker class /wg jun 2025 */
|
|
679
711
|
const bannedGPUs = Array.isArray(worker.config.bannedGPUs) ? worker.config.bannedGPUs : [ worker.config.bannedGPUs ];
|
|
@@ -681,7 +713,7 @@ async function main()
|
|
|
681
713
|
{
|
|
682
714
|
for (let descriptor in banEntry)
|
|
683
715
|
{
|
|
684
|
-
if (banEntry[descriptor].test(
|
|
716
|
+
if (banEntry[descriptor].test(evaluatorInfo.webgpu.info[descriptor]))
|
|
685
717
|
{
|
|
686
718
|
console.error(' * This GPU is not supported; disabling');
|
|
687
719
|
worker.config.cores = { cpu: worker.config.cores.cpu, gpu: 0 };
|
|
@@ -701,20 +733,17 @@ async function main()
|
|
|
701
733
|
}
|
|
702
734
|
else
|
|
703
735
|
{
|
|
704
|
-
worker.runInfo.gpuType =
|
|
736
|
+
worker.runInfo.gpuType = evaluatorInfo.webgpu.info.device;
|
|
705
737
|
worker.runInfo.gpuCores = 1;
|
|
706
738
|
}
|
|
707
739
|
}
|
|
708
740
|
}
|
|
709
741
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
+ `gpu: ${Math.round(worker.config.utilization.gpu * 100)}%`);
|
|
714
|
-
console.info(` . Configured Cores: cpu: ${String(worker.config.cores.cpu).padEnd(3, ' ')} `
|
|
742
|
+
console.info(` . Utilization Target: cpu: ${String(Math.round(worker.config.utilization.cpu * 100)).padStart(3, ' ')}% `
|
|
743
|
+
+ `gpu: ${Math.round(worker.config.utilization.gpu * 100)}%`);
|
|
744
|
+
console.info(` . Configured Cores: cpu: ${String(worker.config.cores.cpu).padEnd(3, ' ')} `
|
|
715
745
|
+ ` gpu: ${worker.config.cores.gpu}`);
|
|
716
|
-
|
|
717
|
-
}
|
|
746
|
+
console.info(` . Maximum Sandboxes: ${worker.config.maxSandboxes}`);
|
|
718
747
|
console.info(' . Supervisor version: ' + worker.supervisorVersion);
|
|
719
748
|
console.info(' . Console type: ' + operatingMode.consoleType);
|
|
720
749
|
console.info(' . Logging: ' + (loggingOptions.loggers.join(', ') || 'none'));
|
|
@@ -730,12 +759,17 @@ async function main()
|
|
|
730
759
|
return;
|
|
731
760
|
require('../lib/check-scheduler-version').check();
|
|
732
761
|
|
|
733
|
-
worker.
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
762
|
+
/* Hold the worker.p$stop promise between the stop and end events, for use by cleanUpThenExit() */
|
|
763
|
+
worker.on('stop', () => {
|
|
764
|
+
debug('dcp-worker:exit')('Trapped DistributiveWorker<stop> stop event with running worker');
|
|
765
|
+
worker.on('error', (error) => {
|
|
766
|
+
debug('dcp-worker:exit')('Trapped DistributiveWorker<error> event after stop event');
|
|
767
|
+
throw error;
|
|
768
|
+
});
|
|
737
769
|
});
|
|
738
770
|
|
|
771
|
+
worker.ref();
|
|
772
|
+
worker.on('start', () => workerStarted = true);
|
|
739
773
|
worker.on('error', function handleWorkerError(error) {
|
|
740
774
|
if (worker.isWorkerError && worker.isWorkerError(error))
|
|
741
775
|
{
|
|
@@ -760,6 +794,7 @@ async function main()
|
|
|
760
794
|
console.error('Unrecoverable', error.code ? `${error.name} (${error.code})` : error.name,
|
|
761
795
|
'- shutting down the worker:',
|
|
762
796
|
process.env.DCP_SUPERVISOR_DEBUG_DISPLAY_MAX_INFO ? error : error.message);
|
|
797
|
+
debug('dcp-worker:error')(error);
|
|
763
798
|
}
|
|
764
799
|
|
|
765
800
|
/* Let the supervisor try to finish slices for up to three minutes after a single unrecoverable error. */
|
|
@@ -782,12 +817,13 @@ async function main()
|
|
|
782
817
|
console.info(` ! not claming earnings in the amount of ${amount} ⊇ (can claim later)`);
|
|
783
818
|
}
|
|
784
819
|
|
|
785
|
-
worker.on('stop', () => { console.log('
|
|
820
|
+
worker.on('stop', () => { console.log(' . Worker is stopping') });
|
|
786
821
|
worker.on('end', () => { console.log(' * Worker has stopped') });
|
|
787
822
|
worker.on('job', job => console.log(` . Job: ${job.name} ${job.id.slice(0,8)} ${job.description || ''} ${job.link || ''}`));
|
|
788
823
|
worker.on('start', () => console.info(' * Ready.\n'));
|
|
789
824
|
|
|
790
|
-
|
|
825
|
+
if (!noStartWorker)
|
|
826
|
+
await worker.start();
|
|
791
827
|
} /* main() */
|
|
792
828
|
|
|
793
829
|
/**
|
|
@@ -863,31 +899,48 @@ async function handleUnhandled(error)
|
|
|
863
899
|
*/
|
|
864
900
|
async function cleanupThenExit(exitCode)
|
|
865
901
|
{
|
|
866
|
-
|
|
867
|
-
if (worker)
|
|
868
|
-
worker.stop(true); /* toggle internal worker state so it won't surprise us by starting sandboxes */
|
|
902
|
+
const pr$end = Promise.withResolvers();
|
|
869
903
|
|
|
870
|
-
|
|
871
|
-
if (
|
|
904
|
+
debug('dcp-worker:exit')('cleanup and exit, code', exitCode);
|
|
905
|
+
if (process.exitCode === exitCodes.lostRef || process.exitCode === exitCodes.normal)
|
|
906
|
+
process.exitCode = exitCode;
|
|
907
|
+
if (!cleanupThenExit.busy)
|
|
908
|
+
cleanupThenExit.busy = true;
|
|
909
|
+
else
|
|
872
910
|
{
|
|
873
|
-
if (!process.exitCode)
|
|
874
|
-
process.exitCode = exitCode;
|
|
875
911
|
debug('dcp-worker:exit')('exit race, bailing on cleanup for exit code', exitCode);
|
|
876
912
|
return;
|
|
877
913
|
}
|
|
878
|
-
|
|
879
|
-
worker = false;
|
|
880
|
-
cleanupThenExit.busy = true;
|
|
881
|
-
process.exitCode = exitCode;
|
|
882
|
-
|
|
883
914
|
/* Final event loop reference; keeps the process alive while the loggers unhook */
|
|
884
915
|
setTimeout(() => {
|
|
885
|
-
|
|
916
|
+
debug('dcp-worker:exit')('cleanup timeout expired');
|
|
917
|
+
console.warn(' *** cleanup timeout expired ***');
|
|
886
918
|
process.exit();
|
|
887
919
|
}, 10 * 1e3).ref();
|
|
888
920
|
|
|
921
|
+
if (!worker || !workerStarted || worker.inspect.stopped)
|
|
922
|
+
{
|
|
923
|
+
debug('dcp-worker:exit')('cleanup will not wait for DistributiveWorker<end> event');
|
|
924
|
+
pr$end.resolve();
|
|
925
|
+
}
|
|
926
|
+
else
|
|
927
|
+
{
|
|
928
|
+
debug('dcp-worker:exit')('cleanup will wait for DistributiveWorker<end> event');
|
|
929
|
+
worker.once('end', pr$end.resolve);
|
|
930
|
+
worker.once('error', pr$end.reject);
|
|
931
|
+
worker.stop(true); /* toggle internal worker state so it won't surprise us by starting sandboxes */
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
console.info(' ! begin shutdown, exit code =', exitCode);
|
|
935
|
+
const p$workerShutdownTasks = Promise.all([
|
|
936
|
+
require('../lib/p2p-shared').shutdown(),
|
|
937
|
+
utils.noteWorkerShutdown(worker),
|
|
938
|
+
worker?.p$stop,
|
|
939
|
+
]);
|
|
940
|
+
|
|
889
941
|
try
|
|
890
942
|
{
|
|
943
|
+
debug('dcp-worker:exit')('unhooking process events');
|
|
891
944
|
process.off('SIGESC', handleSigDeath);
|
|
892
945
|
process.off('SIGINT', handleSigDeath);
|
|
893
946
|
process.off('SIGTERM', handleSigDeath);
|
|
@@ -895,11 +948,18 @@ async function cleanupThenExit(exitCode)
|
|
|
895
948
|
process.off('unhandledRejection', handleUnhandled);
|
|
896
949
|
process.off('uncaughtException', handleUnhandled);
|
|
897
950
|
if (console.close)
|
|
951
|
+
{
|
|
952
|
+
debug('dcp-worker:exit')('closing console');
|
|
898
953
|
console.close();
|
|
899
|
-
|
|
954
|
+
}
|
|
955
|
+
debug('dcp-worker:exit')('waiting for DistributiveWorker<end> event');
|
|
956
|
+
await pr$end.promise;
|
|
957
|
+
debug('dcp-worker:exit')('unhooking loggers');
|
|
958
|
+
await loggers.unhook()
|
|
959
|
+
.then(() => debug('dcp-worker:exit')('loggers unhooked'))
|
|
900
960
|
.catch(error => { console.error('Error unhooking loggers:', error) })
|
|
901
961
|
.finally(async () => {
|
|
902
|
-
await p$
|
|
962
|
+
await p$workerShutdownTasks.catch(console.error);
|
|
903
963
|
debug('dcp-worker:exit')('done cleanup, exitCode=' + process.exitCode);
|
|
904
964
|
process.exit();
|
|
905
965
|
});
|
|
@@ -939,6 +999,7 @@ async function handleSigDeath(signalName, signal)
|
|
|
939
999
|
});
|
|
940
1000
|
}
|
|
941
1001
|
|
|
1002
|
+
noStartWorker = true; /* sigint before worker.start should not start worker */
|
|
942
1003
|
const warning = signal
|
|
943
1004
|
? `\ntrapped ${signalName}, signal ${signal}`
|
|
944
1005
|
: `\ntrapped ${signalName === 'SIGESC' ? '<esc>' : signalName}`;
|