dcp-worker 3.3.19 → 4.0.1

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/README.md CHANGED
@@ -32,7 +32,7 @@ This document was last updated Sep 12, 2024.
32
32
  | bin/dcp-worker | Program which requests work from the scheduler and coordinates its evaluation in a secure environment called dcp-evaluator-v8
33
33
  | bin/dcp-evaluator-start | Program which launches dcp-evaluator-v8
34
34
  | bin/dcp-evaluator-manager | Program which which manages the launching of dcp-evaluator-v8; e.g. based on system load, terminal activity, screensaver activity, etc.
35
- | etc/dcp-worker-config.js | Default configuration for dcp-worker
35
+ | examples/dcp-config.js | Default configuration for dcp-worker, copy to /etc/dcp/overrides/dcp-worker to override sections
36
36
 
37
37
  ### Related Packages
38
38
  - dcp-evaluator-v8, our isolated JS/WASM/WebGPU evaluation environment, ships separately. Installing dcp-worker with your system's package manager will automatically install dcp-evaluator-v8 as a dependency.
@@ -527,6 +527,12 @@ async function main()
527
527
  const parser = new getopt.BasicParser('h(help)P:(prefix)d:(disable-monitor)l:(max-load)r:(rate)Li:ap:s:(signal)T:(loadavg-type)f:(pidfile)', process.argv);
528
528
  var option;
529
529
 
530
+ if (dcpConfig.evaluator.listen)
531
+ {
532
+ daemonConfig.net.hostname = dcpConfig.evaluator.listen.hostname;
533
+ daemonConfig.net.port = dcpConfig.evaluator.listen.port;
534
+ }
535
+
530
536
  while ((option = parser.getopt()) !== undefined)
531
537
  {
532
538
  switch (option.option)
@@ -655,9 +661,8 @@ async function main()
655
661
 
656
662
  /* Initialize dcp-client to use only local resources before launching the main function */
657
663
  require('dcp-client').init({
658
- progName: 'dcp-worker',
664
+ programName: 'dcp-worker',
659
665
  parseArgv: false,
660
- configName: process.env.DCP_CONFIG || '../etc/dcp-worker-config', /* => .js or .json */
661
666
  dcpConfig: {
662
667
  scheduler: { configLocation: false },
663
668
  bundle: { location: false },
@@ -274,8 +274,7 @@ function main() {
274
274
 
275
275
  /* Initialize dcp-client to use only local resources before launching the main function */
276
276
  require('dcp-client').init({
277
- progName: 'dcp-worker',
278
- configName: process.env.DCP_CONFIG || '../etc/dcp-worker-config',
277
+ programName: 'dcp-worker',
279
278
  dcpConfig: {
280
279
  scheduler: { configLocation: false },
281
280
  bundle: { location: false },
@@ -276,7 +276,7 @@ function cpuCommaGpu(str)
276
276
  * - dumpConfig
277
277
  * - workerId
278
278
  */
279
- async function processOptions()
279
+ async function processOptions(workerConfig)
280
280
  {
281
281
  const opts = { verbose: 0 };
282
282
  const parser = new getopt.BasicParser('h(help)C(dumpConfig)S:(set)M:(merge)a:(allowedOrigins)'
@@ -319,35 +319,35 @@ async function processOptions()
319
319
  break;
320
320
 
321
321
  case 'a':
322
- dcpConfig.worker.allowedOrigins.any.push(opthnd.optarg);
322
+ workerConfig.allowOrigins.any.push(opthnd.optarg);
323
323
  break;
324
324
 
325
325
  case 'c':
326
- Object.assign(dcpConfig.worker.cores, cpuCommaGpu(opthnd.optarg));
326
+ Object.assign(workerConfig.cores, cpuCommaGpu(opthnd.optarg));
327
327
  break;
328
328
 
329
329
  case 'u':
330
- Object.assign(dcpConfig.worker.utilization, cpuCommaGpu(opthnd.optarg));
330
+ Object.assign(workerConfig.utilization, cpuCommaGpu(opthnd.optarg));
331
331
  break;
332
332
 
333
333
  case 'm':
334
- dcpConfig.worker.maxSandboxes = Number(opthnd.optarg);
334
+ workerConfig.maxSandboxes = Number(opthnd.optarg);
335
335
  break;
336
336
 
337
337
  case 'J':
338
- dcpConfig.worker.jobAddresses = (dcpConfig.worker.jobAddresses || []).concat(opthnd.optarg);
338
+ workerConfig.jobAddresses = (workerConfig.jobAddresses || []).concat(opthnd.optarg);
339
339
  break;
340
340
 
341
341
  case 'j': /** @todo integrate with upcoming scheduler changes to opaqueId /wg dec 2024 */
342
- dcpConfig.worker.jobs = (dcpConfig.worker.jobs || []).concat(opthnd.optarg);
342
+ workerConfig.jobs = (workerConfig.jobs || []).concat(opthnd.optarg);
343
343
  break;
344
344
 
345
345
  case 'G':
346
- dcpConfig.worker.leavePublicGroup = true;
346
+ workerConfig.leavePublicGroup = true;
347
347
  break;
348
348
 
349
349
  case 'H':
350
- dcpConfig.evaluator.location.hostname = opthnd.ortarg;
350
+ dcpConfig.evaluator.location.hostname = opthnd.optarg;
351
351
  break;
352
352
 
353
353
  case 'p':
@@ -360,9 +360,9 @@ async function processOptions()
360
360
  const joinHash = joinSecret;
361
361
 
362
362
  if (isHash(joinHash))
363
- dcpConfig.worker.computeGroups.push({ joinKey, joinHash });
363
+ workerConfig.computeGroups.push({ joinKey, joinHash });
364
364
  else
365
- dcpConfig.worker.computeGroups.push({ joinKey, joinSecret });
365
+ workerConfig.computeGroups.push({ joinKey, joinSecret });
366
366
  break;
367
367
  }
368
368
 
@@ -380,7 +380,7 @@ async function processOptions()
380
380
  {
381
381
  /* merge mode: objects are merged at the property level, except for arrays, which are concatenated */
382
382
  if (confNode === dcpConfig.worker && (prop === 'worktimes' || prop === 'capabilities'))
383
- await probeEvaluator(); /* ensure we have something to merge into */
383
+ await probeEvaluator(dcpConfig.worker); /* ensure we have something to merge into */
384
384
  switch(typeof confNode[prop])
385
385
  {
386
386
  case 'object':
@@ -408,8 +408,8 @@ async function processOptions()
408
408
  {
409
409
  const wallet = require('dcp/wallet');
410
410
  const snapshot = readWorkerSnapshot();
411
- dcpConfig.worker = snapshot.workerConfig;
412
- dcpConfig.worker.paymentAddress = new wallet.Address(dcpConfig.worker.paymentAddress);
411
+ workerConfig = snapshot.workerConfig;
412
+ workerConfig.paymentAddress = new wallet.Address(workerConfig.paymentAddress);
413
413
  }
414
414
  }
415
415
  }
@@ -422,23 +422,35 @@ async function processOptions()
422
422
  * as late as possible during the configuration phase so that the user has the option to specify these
423
423
  * completely on a system with no evaluator.
424
424
  */
425
- async function probeEvaluator()
425
+ async function probeEvaluator(workerConfig)
426
426
  {
427
+ var evaluatorInfo;
427
428
  if (probeEvaluator.probed)
428
429
  return;
429
430
  probeEvaluator.probed = true;
430
- const probeTimer = setTimeout(() => panic('unable to probe evaluator'), 66610e3); /* Need to keep main from exiting */
431
431
 
432
- if (!dcpConfig.worker.capabilities || !dcpConfig.worker.worktimes)
432
+ if (!workerConfig.capabilities || !workerConfig.worktimes)
433
433
  {
434
+ const probeTimer = setTimeout(() => panic('unable to probe evaluator'), 66610e3); /* Need to keep main from exiting */
434
435
  const { workerFactory } = require('dcp-client/lib/standaloneWorker');
435
436
  debug('dcp-task-probe:evaluator')('Probing evaluator at', dcpConfig.evaluator.location);
436
- const evaluatorInfo = await require('dcp/worker').probeEvaluator(workerFactory(dcpConfig.evaluator.location));
437
- dcpConfig.worker.capabilities ||= evaluatorInfo.capabilities;
438
- dcpConfig.worker.worktimes ||= evaluatorInfo.worktimes;
439
- }
437
+ try
438
+ {
439
+ evaluatorInfo = await require('dcp/worker').probeEvaluator(workerFactory(dcpConfig.evaluator.location));
440
+ }
441
+ catch(error)
442
+ {
443
+ console.warn(`Warning: unable to probe evaluator at ${dcpConfig.evaluator.location} (${error.message + (error.code ? ' ' + error.code : '')})`);
444
+ return;
445
+ }
446
+ finally
447
+ {
448
+ clearTimeout(probeTimer);
449
+ }
440
450
 
441
- clearTimeout(probeTimer);
451
+ workerConfig.capabilities ||= evaluatorInfo.capabilities;
452
+ workerConfig.worktimes ||= evaluatorInfo.worktimes;
453
+ }
442
454
  }
443
455
 
444
456
  /**
@@ -470,12 +482,11 @@ function readWorkerSnapshot()
470
482
  */
471
483
  function makeComputeGroupsRequest(tdConn, dummyWorker)
472
484
  {
473
- const computeGroups = structuredClone(dcpConfig.worker.computeGroups); /* supervisor code sadly mutates this /wg dec 2024 */
474
- const options = Object.assign({}, dcpConfig.worker, { computeGroups });
485
+ const options = Object.assign({}, dummyWorker.config);
475
486
  const taskDistributor = { connection: tdConn };
476
487
 
477
488
  dummyWorker.badSupervisorBackdoor.dcp4.generateWorkerComputeGroups.apply({ taskDistributor, options });
478
- if (!dcpConfig.worker.leavePublicGroup && !dcpConfig.worker.leaveGlobalGroup)
489
+ if (!dummyWorker.config.leavePublicGroup && !dummyWorker.config.leaveGlobalGroup)
479
490
  options.computeGroups.unshift({ joinKey: 'public' });
480
491
  return options.computeGroups;
481
492
  }
@@ -485,17 +496,14 @@ function makeComputeGroupsRequest(tdConn, dummyWorker)
485
496
  * Request a task from the task distributor
486
497
  *
487
498
  * @todo unify with supervisor /wg dec 2024
488
- * @param {Keystore} identity identity of the requesting entity
489
499
  * @param {Object} opts command-line options to dcp-task-probe
490
500
  * .replay truey to use request from worker snapshot instead of a generated request
491
501
  * .workerId workerId for request
492
502
  */
493
- async function requestTask(identity, opts)
503
+ async function requestTask(dummyWorker, opts)
494
504
  {
495
505
  const protocol = require('dcp/protocol');
496
- const worker = require('dcp/worker');
497
506
  const tdConn = new protocol.Connection(dcpConfig.scheduler.services.taskDistributor);
498
- const dummyWorker = new worker.Worker(identity, dcpConfig.worker); /* side effect: initializes dcpConfig.worker */
499
507
  var request;
500
508
 
501
509
  if (opts.replay)
@@ -504,29 +512,29 @@ async function requestTask(identity, opts)
504
512
  request = {
505
513
  supervisor: dummyWorker.supervisorVersion,
506
514
  targetLoad: {
507
- cpu: Math.min(dcpConfig.worker.maxSandboxes, dcpConfig.worker.cores.cpu * dcpConfig.worker.utilization.cpu) /* cpuCoreSpace */,
508
- gpu: Math.min(dcpConfig.worker.maxSandboxes, dcpConfig.worker.cores.gpu * dcpConfig.worker.utilization.gpu) /* this.maxWorkingGPUs */,
509
- longSlices: dcpConfig.worker.maxSandboxes /* Math.floor(cpuCoreSpace) */,
515
+ cpu: Math.min(dummyWorker.config.maxSandboxes, dummyWorker.config.cores.cpu * dummyWorker.config.utilization.cpu) /* cpuCoreSpace */,
516
+ gpu: Math.min(dummyWorker.config.maxSandboxes, dummyWorker.config.cores.gpu * dummyWorker.config.utilization.gpu) /* this.maxWorkingGPUs */,
517
+ longSlices: dummyWorker.config.maxSandboxes /* Math.floor(cpuCoreSpace) */,
510
518
  },
511
519
  coreStats: { /** @todo why are we specifying these? /wg dec 2024 */
512
- worker: dummyWorker.workerId,
520
+ worker: dummyWorker.id,
513
521
  lCores: require('os').cpus().length,
514
522
  pCores: require('physical-cpu-count'),
515
- sandbox: dcpConfig.worker.maxSandboxes,
523
+ sandbox: dummyWorker.config.maxSandboxes,
516
524
  },
517
525
  jobQuanta: [ 1 ]/* this.quanta.calculateJobQuanta() */,
518
- capabilities: dcpConfig.worker.capabilities,
519
- paymentAddress: dcpConfig.worker.paymentAddress,
520
- jobAddresses: dcpConfig.worker.jobAddresses || [],
526
+ capabilities: dummyWorker.config.capabilities,
527
+ paymentAddress: dummyWorker.config.paymentAddress,
528
+ jobAddresses: dummyWorker.config.jobAddresses || [],
521
529
  workerComputeGroups: makeComputeGroupsRequest(tdConn, dummyWorker),
522
- minimumWage: dcpConfig.worker.minimumWage,
530
+ minimumWage: dummyWorker.config.minimumWage,
523
531
  soteriaJobs: [],
524
532
  overdueSlices: [],
525
533
  previouslyWorkedJobs: [], /* discrete jobs */
526
534
  rejectedJobs: [],
527
535
  unresolvedJobs: [],
528
536
  fetchState: 1, /* normal fetch */
529
- worktimes: dcpConfig.worker.worktimes,
537
+ worktimes: dummyWorker.config.worktimes,
530
538
  };
531
539
 
532
540
  debug('dcp-task-probe:connect')('Connecting to task distributor at', tdConn.targetDescriptor.location.href);
@@ -542,7 +550,8 @@ async function requestTask(identity, opts)
542
550
  if (!response.success)
543
551
  panic('request failed:', response.payload);
544
552
 
545
- return { response, workerId: request.coreStats?.worker };
553
+ debugger;
554
+ return { response, workerId: request.coreStats?.worker, workerConfig: dummyWorker.config };
546
555
  }
547
556
 
548
557
  async function returnTask(taskResponsePayload)
@@ -596,26 +605,35 @@ function fmtMs(ms)
596
605
  /** Main program entry point */
597
606
  async function main()
598
607
  {
599
- const wallet = require('dcp/wallet');
600
- const identity = await wallet.getId();
601
- const opts = await processOptions();
608
+ const wallet = require('dcp/wallet');
609
+ const identity = require('dcp/identity');
610
+
611
+ const initialWorkerConfig = {
612
+ allowOrigins: {
613
+ any: [],
614
+ }
615
+ };
616
+ const opts = await processOptions(initialWorkerConfig);
617
+ await identity.login('$login');
602
618
 
603
- if (!dcpConfig.worker.paymentAddress)
604
- dcpConfig.worker.paymentAddress = (await wallet.get()).address;
619
+ if (typeof initialWorkerConfig.paymentAddress === 'string')
620
+ initialWorkerConfig.paymentAddress = new wallet.Address(initialWorkerConfig.paymentAddress);
621
+ else if (!initialWorkerConfig.paymentAddress)
622
+ initialWorkerConfig.paymentAddress = (await wallet.get({ oAuth: false })).address;
605
623
 
606
624
  if (!opts.replay)
607
- await probeEvaluator();
625
+ await probeEvaluator(initialWorkerConfig);
626
+ const dummyWorker = new (require('dcp/worker').DistributiveWorker)(initialWorkerConfig, function FakeSandboxConstructor(){});
608
627
 
609
628
  if (opts.dumpConfig)
610
629
  {
611
- /* work around the cores getter/setter that is added by the worker */
612
- const dump = Object.assign({}, dcpConfig.worker);
613
- dump.cores = { cpu: dcpConfig.worker.cores.cpu, gpu: dcpConfig.worker.cores.gpu };
630
+ /* work around the cores getter/setter */
631
+ const dump = Object.assign({}, dummyWorker.config);
614
632
  console.log(dump);
615
633
  process.exit(0);
616
634
  }
617
635
 
618
- const { workerId, response } = await requestTask(identity, opts);
636
+ const { workerId, response, workerConfig } = await requestTask(dummyWorker, opts);
619
637
  const task = response.payload?.body?.task;
620
638
  if (task)
621
639
  await returnTask(response.payload);
@@ -623,7 +641,10 @@ async function main()
623
641
  console.log('Task Distributor: ', dcpConfig.scheduler.services.taskDistributor.location.href);
624
642
  console.log('Result Submitter: ', dcpConfig.scheduler.services.resultSubmitter.location.href);
625
643
  console.log('Worker Id: ', workerId);
626
- console.log('DCP Address: ', String(identity.address));
644
+ console.log('Max Sandboxes: ', workerConfig.maxSandboxes);
645
+ console.log('Cores: ', Object.assign({}, workerConfig.cores));
646
+ console.log('Utilization: ', workerConfig.utilization);
647
+ console.log('DCP Address: ', String(identity.get().address));
627
648
 
628
649
  if (!task)
629
650
  {
@@ -647,8 +668,8 @@ async function main()
647
668
  fmtMs(Object.keys(task).map(jobId => newJobs[jobId].metrics.sliceCPUTime).reduce((a, b) => a+b, 0)) + ',',
648
669
  fmtMs(Object.keys(task).map(jobId => newJobs[jobId].metrics.sliceGPUTime).reduce((a, b) => a+b, 0)));
649
670
  console.log('CPU,GPU Time/core: ',
650
- fmtMs(Object.keys(task).map(jobId => newJobs[jobId].metrics.sliceCPUTime).reduce((a, b) => a+b, 0) / dcpConfig.worker.cores.cpu) + ',',
651
- fmtMs(Object.keys(task).map(jobId => newJobs[jobId].metrics.sliceGPUTime).reduce((a, b) => a+b, 0) / dcpConfig.worker.cores.gpu));
671
+ fmtMs(Object.keys(task).map(jobId => newJobs[jobId].metrics.sliceCPUTime).reduce((a, b) => a+b, 0) / workerConfig.cores.cpu) + ',',
672
+ fmtMs(Object.keys(task).map(jobId => newJobs[jobId].metrics.sliceGPUTime).reduce((a, b) => a+b, 0) / workerConfig.cores.gpu));
652
673
  console.log('Task Duration: ', schedulerConfig.targetTaskDuration + 's');
653
674
  console.log('Compute Groups: ', Object.keys(computeGroupJobs).length);
654
675
 
@@ -690,7 +711,6 @@ async function main()
690
711
 
691
712
  /* Initialize dcp-client to use only local resources before launching the main function */
692
713
  require('dcp-client').init({
693
- progName: 'dcp-worker',
714
+ programName: 'dcp-worker',
694
715
  parseArgv: false,
695
- configName: process.env.DCP_CONFIG || '../etc/dcp-worker-config', /* => .js or .json */
696
716
  }).then(main);
package/bin/dcp-worker CHANGED
@@ -1,4 +1,5 @@
1
1
  #! /usr/bin/env node
2
+
2
3
  /**
3
4
  * @file dcp-worker.js
4
5
  * Standalone NodeJS DCP Worker
@@ -18,14 +19,11 @@ var worker;
18
19
  const process = require('process');
19
20
  const fs = require('fs');
20
21
  const path = require('path');
21
- const crypto = require('crypto');
22
- const chalk = require('chalk');
23
22
  const telnetd = require('../lib/remote-console');
24
23
 
25
24
  const { slicesFetched, debugging, displayMaxDiagInfo } = require('../lib/utils');
26
- const { a$sleep } = require('dcp/utils');
25
+ const { a$sleep, leafMergeInto } = require('dcp/utils');
27
26
 
28
- const configName = process.env.DCP_CONFIG || '../etc/dcp-worker-config';
29
27
  const EXIT_UNHANDLED = 5;
30
28
  const systemStateInfo = globalThis.systemStateInfo = {};
31
29
 
@@ -45,15 +43,7 @@ const replHelpers = {
45
43
  },
46
44
  };
47
45
  telnetd.init(replHelpers);
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
- }
46
+ require('dcp-client').init().then(main).catch(handleUnhandled);
57
47
 
58
48
  /**
59
49
  * Output startup banner message. Currently a wrapper for console.log, future plans are to make it
@@ -66,12 +56,6 @@ function bannerLog()
66
56
  }
67
57
  bannerLog.cumulative = [];
68
58
 
69
- /* Initialize dcp-client with local config defaults and run the main function. DCP_CONFIG_COOKIE becomes dcpConfig.cookie.
70
- * And dcpConfig is defined as a side effect of initializing dcp-client.
71
- */
72
- process.env.DCP_CONFIG_COOKIE = (Math.random().toString(16)).slice(2) + '-' + process.pid + '-' + Date.now();
73
- require('dcp-client').init({ configName }).then(main).catch(handleUnhandled);
74
-
75
59
  function parseCliArgs()
76
60
  {
77
61
  var defaultPidFileName;
@@ -85,10 +69,6 @@ function parseCliArgs()
85
69
  describe: 'The address to deposit funds into, will use the default bank keystore if not provided.',
86
70
  type: 'string',
87
71
  },
88
- defaultPaymentAddressToDCP: {
89
- describe: 'If this option is set and no other payment address is provided, send payment for work completed to the DCP Community account',
90
- type: 'boolean',
91
- },
92
72
  cores: {
93
73
  alias: 'c',
94
74
  describe: 'Number of CPU and GPU cores to work with: the format is 7,1 (or just 7) for 7 CPU cores and 1 GPU',
@@ -185,7 +165,7 @@ function parseCliArgs()
185
165
 
186
166
  showConfig: {
187
167
  hide: false,
188
- describe: 'Show merged configuration node (e.g., --showConfig worker)',
168
+ describe: 'Show worker config',
189
169
  type: 'string',
190
170
  },
191
171
 
@@ -256,20 +236,6 @@ function isHash(b) {
256
236
  return b && b.length === 68 && b.startsWith('eh1-');
257
237
  }
258
238
 
259
- /**
260
- * Add one or more configuration objects into a target via leaf-merging.
261
- */
262
- function addConfig(target, ...objs)
263
- {
264
- const { leafMerge } = require('dcp/utils');
265
- var tmp = target;
266
-
267
- for (let obj of objs)
268
- tmp = leafMerge(tmp, obj);
269
-
270
- Object.assign(target, tmp);
271
- }
272
-
273
239
  /**
274
240
  * Replacement for process.exit() that tries to increase the probability
275
241
  * that remote log messages will make it out over the network.
@@ -289,17 +255,28 @@ function processExit()
289
255
  */
290
256
  async function main()
291
257
  {
292
- const wallet = require('dcp/wallet');
293
- const DCPWorker = require('dcp/worker').Worker;
258
+ const wallet = require('dcp/wallet');
259
+ const identity = require('dcp/identity');
260
+ const { DistributiveWorker } = require('dcp/worker');
261
+ var workerConfig = {};
294
262
  const cliArgs = parseCliArgs();
263
+ telnetd.setMainEval(function mainEval() { return eval(arguments[0]) }); // eslint-disable-line no-eval
264
+ require('../lib/startWorkerLogger').init(cliArgs); /* Start remote logger as early as possible */
265
+
266
+ /* Process any identity overrides and then establish our identity. */
267
+ identity.interactive = false;
268
+ if (cliArgs.identityKey || cliArgs.identityKeystore)
269
+ await identity.set(cliArgs.identityKey || cliArgs.identityKeystore);
270
+ await identity.login('$login');
271
+
272
+ /* Eagerly create a worker object and mutate its config property to reflect argv before starting it. */
295
273
  const sawOptions = {
296
274
  hostname: cliArgs.hostname,
297
275
  port: cliArgs.port
298
276
  };
299
-
300
- telnetd.setMainEval(function mainEval() { return eval(arguments[0]) }); // eslint-disable-line no-eval
301
- require('../lib/startWorkerLogger').init(cliArgs); /* Start remote logger as early as possible */
302
- verifyDefaultConfigIntegrity(); /* Bail before TUI & as early as possible if bad conf */
277
+ if (typeof dcpConfig.worker.cleanupTimeout !== 'number')
278
+ dcpConfig.worker.cleanupTimeout = 60;
279
+ const SandboxConstructor = require('dcp-client/lib/standaloneWorker').workerFactory(sawOptions);
303
280
 
304
281
  process.on('SIGINT', handleSigDeath);
305
282
  process.on('SIGTERM', handleSigDeath);
@@ -307,74 +284,26 @@ async function main()
307
284
  process.on('unhandledRejection', handleUnhandled);
308
285
  process.on('uncaughtException', handleUnhandled);
309
286
 
310
- const getOpts = {};
311
- if (cliArgs.defaultPaymentAddressToDCP)
312
- getOpts.oAuth = false;
313
-
314
- let paymentAddress = false
315
- || cliArgs.paymentAddress
316
- || dcpConfig.worker.paymentAddress
317
- || (await wallet.get(getOpts).catch(error => {
318
- // if flag is set and no other address is provided, use the DCP Community Account,
319
- // which is 0x079DAC0612C710ab4e975dAb7171C7e4beF78c5a at time of writing
320
- if ((error.code === 'ENOENT') && cliArgs.defaultPaymentAddressToDCP)
321
- {
322
- console.warn('Warning: Defaulting payment to DCP Community Account');
323
- return {address:'0x079DAC0612C710ab4e975dAb7171C7e4beF78c5a'};
324
- }
325
- throw error;
326
- })).address;
327
- if (typeof paymentAddress === 'string')
328
- paymentAddress = new wallet.Address(paymentAddress);
287
+ if (cliArgs.paymentAddress)
288
+ workerConfig.paymentAddress = new wallet.Address(cliArgs.paymentAddress);
289
+ else if (typeof workerConfig.paymentAddress === 'string')
290
+ workerConfig.paymentAddress = new wallet.Address(workerConfig.paymentAddress);
291
+ else if (!workerConfig.paymentAddress)
292
+ workerConfig.paymentAddress = (await wallet.get({ oAuth: false })).address;
329
293
 
330
294
  if (cliArgs.pidFile)
331
295
  require('../lib/pidfile').write(cliArgs.pidFile);
332
296
 
333
- /* Figure out the worker's identity and put that keystore in the wallet */
334
- let identityKeystore = false;
335
- if (cliArgs.identityKey)
336
- identityKeystore = await new wallet.IdKeystore(cliArgs.identityKey, '');
337
- else if (cliArgs.identityKeystore)
338
- identityKeystore = await new wallet.IdKeystore(JSON.parse(cliArgs.identityKeystore), '');
339
- else
340
- identityKeystore = await wallet.getId();
341
- await wallet.addId(identityKeystore);
342
-
343
- /* Build the worker options, which are largely given by dcpConfig.worker. We use a reference for
344
- * dcpConfig.worker rather than copying it, so that runtime modifications to the worker configuration
345
- * in memory take effect immediately.
346
- *
347
- * forceOptions override any setting in dcpConfig; this can be used for settings calculated above
348
- * which were derived from dcpConfig in the first place. defaultOptions are overrideable by the usual
349
- * dcpConfig mechanisms, but since they are dynamic (or non-user-facing) they don't come from the
350
- * etc/dcp-worker-config.js file that ships with the work.
351
- *
352
- * It is important to never disable leavePublicGroup as a side effect of any other operation, or
353
- * slight configuration errors could have large security impacts.
354
- z */
355
- const dcpWorkerOptions = dcpConfig.worker;
356
- const forceOptions = {
357
- paymentAddress,
358
- };
359
- const defaultOptions = {
360
- sandboxOptions: {
361
- SandboxConstructor: require('dcp-client/lib/standaloneWorker').workerFactory(sawOptions)
362
- },
363
- };
364
-
365
297
  if (cliArgs.leavePublicGroup !== undefined)
366
- forceOptions.leavePublicGroup = mkBool(cliArgs.leavePublicGroup);
298
+ workerConfig.leavePublicGroup = mkBool(cliArgs.leavePublicGroup);
367
299
  if (cliArgs.publicGroupFallback !== undefined)
368
- forceOptions.publicGroupFallback = mkBool(cliArgs.publicGroupFallback);
369
-
370
- addConfig(dcpWorkerOptions, defaultOptions, dcpConfig.worker, forceOptions);
371
- processCoresAndMaxSandboxes(dcpWorkerOptions, cliArgs);
300
+ workerConfig.publicGroupFallback = mkBool(cliArgs.publicGroupFallback);
372
301
 
373
302
  /* Support magic value used by Windows screensaver configuration /wg June 2023 */
374
- if (dcpWorkerOptions.leavePublicGroup === 'fallback')
303
+ if (workerConfig.leavePublicGroup === 'fallback')
375
304
  {
376
- dcpWorkerOptions.publicGroupFallback = true;
377
- dcpWorkerOptions.leavePublicGroup = undefined;
305
+ workerConfig.publicGroupFallback = true;
306
+ workerConfig.leavePublicGroup = undefined;
378
307
  }
379
308
 
380
309
  /* cliArgs.join is the list of compute groups to join */
@@ -388,32 +317,21 @@ z */
388
317
  })
389
318
  .filter((el) => el.joinKey); /* Filter out entries with no joinKey */
390
319
 
391
- addConfig(dcpWorkerOptions.computeGroups, dcpWorkerOptions.computeGroups, cliComputeGroups);
320
+ leafMergeInto(workerConfig.computeGroups, cliComputeGroups);
392
321
  }
393
322
 
394
323
  if (cliArgs.jobId)
395
324
  {
396
- if (dcpWorkerOptions.jobAddresses === false || dcpWorkerOptions.jobAddresses === undefined)
397
- dcpWorkerOptions.jobAddresses = [];
398
- dcpWorkerOptions.jobAddresses.push(...cliArgs.jobId);
325
+ if (!workerConfig.jobAddresses)
326
+ workerConfig.jobAddresses = [];
327
+ workerConfig.jobAddresses.push(...cliArgs.jobId);
399
328
  }
400
329
 
401
330
  if (cliArgs.allowedOrigins)
402
- {
403
- if (!dcpWorkerOptions.allowOrigins)
404
- dcpWorkerOptions.allowOrigins = {};
405
- if (!dcpWorkerOptions.allowOrigins.any)
406
- dcpWorkerOptions.allowOrigins.any = [];
407
- dcpWorkerOptions.allowOrigins.any.push(...cliArgs.allowedOrigins);
408
- }
409
- if (cliArgs.watchdogInterval)
410
- dcpWorkerOptions.watchdogInterval = cliArgs.watchdogInterval;
331
+ workerConfig.allowOrigins.any.push(...cliArgs.allowedOrigins);
411
332
 
412
- if (cliArgs.showConfig)
413
- {
414
- console.log(eval('dcpConfig.' + cliArgs.showConfig));
415
- process.exit();
416
- }
333
+ if (cliArgs.watchdogInterval)
334
+ workerConfig.watchdogInterval = cliArgs.watchdogInterval;
417
335
 
418
336
  if (cliArgs.dumpConfig)
419
337
  {
@@ -421,34 +339,31 @@ z */
421
339
  process.exit();
422
340
  }
423
341
 
424
- if (dcpConfig.worker?.bannedGPUs)
342
+ worker = new DistributiveWorker(workerConfig, SandboxConstructor);
343
+ workerConfig = null; /* bug-finder */
344
+ processCoresAndMaxSandboxes(worker.config, cliArgs);
345
+
346
+ if (cliArgs.showConfig)
425
347
  {
426
- for (let prop in dcpConfig.worker.bannedGPUs)
427
- {
428
- if (!bannedGPUs[prop])
429
- bannedGPUs[prop] = dcpConfig.worker?.bannedGPUs[prop];
430
- else
431
- bannedGPUs[prop] = new RegExp(`(${dcpConfig.worker?.bannedGPUs[prop].source})|(${bannedGPUs[prop].source})`);
432
- }
348
+ console.log(eval('dcpConfig.' + cliArgs.showConfig)); // eslint-disable-line no-eval
349
+ process.exit();
433
350
  }
434
351
 
435
- const nascentWorker = new DCPWorker(identityKeystore, dcpWorkerOptions);
436
- bannerLog(` * Starting DCP Worker ${nascentWorker.workerId}`);
352
+ bannerLog(` * Starting Distributive Worker ${worker.id}`);
437
353
  bannerLog(` . Using evaluator at ${dcpConfig.evaluator.location}`);
438
354
  bannerLog(` . Configured for scheduler ${dcpConfig.scheduler.location}`);
439
355
  bannerLog(` . Bank is ${dcpConfig.bank.location}`);
440
- bannerLog(` . Earned funds will be deposited in account ${nascentWorker.paymentAddress}`);
441
- bannerLog(` . Identity is ${nascentWorker.identityKeystore.address}`);
356
+ bannerLog(` . Earned funds will be deposited in account ${worker.config.paymentAddress}`);
357
+ bannerLog(` . Identity is ${identity.get()?.address}`);
442
358
 
443
- nascentWorker.on('warning', (...payload) => console.warn (...payload));
444
- nascentWorker.on('stop', () => { console.log('Worker is stopping') });
445
- nascentWorker.on('end', () => { logClosing('log', 'Worker has stopped') });
446
- nascentWorker.on('job', job => console.log(` . Job: ${job.name} ${job.address.slice(0,8)} ${job.description || ''} ${job.link || ''}`));
359
+ worker.on('warning', (...payload) => console.warn (...payload));
360
+ worker.on('stop', () => { console.log('Worker is stopping') });
361
+ worker.on('end', () => { logClosing('log', 'Worker has stopped') });
362
+ worker.on('job', job => console.log(` . Job: ${job.name} ${job.address.slice(0,8)} ${job.description || ''} ${job.link || ''}`));
447
363
 
448
364
  // Display clean diagnostic when not debugging and env var
449
365
  // DCP_SUPERVISOR_DEBUG_DISPLAY_MAX_INFO isn't set.
450
- nascentWorker.on('error', (error) => {
451
-
366
+ worker.on('error', (error) => {
452
367
  if (displayMaxDiagInfo())
453
368
  console.error(error);
454
369
  else
@@ -462,36 +377,36 @@ z */
462
377
  console.error(`Error: ${error.message} ${location}`);
463
378
  }
464
379
  });
465
- require('../lib/default-ui-events').hook(nascentWorker, cliArgs);
380
+ require('../lib/default-ui-events').hook(worker, cliArgs);
466
381
 
467
382
  if (cliArgs.outputMode === 'dashboard')
468
- require('../lib/dashboard-tui').init(nascentWorker, cliArgs, bannerLog.cumulative);
383
+ require('../lib/dashboard-tui').init(worker, cliArgs, bannerLog.cumulative);
469
384
 
470
385
  /* Let incorrect event-loop references keep us alive when linked with a debug library, but
471
386
  * exit quickly/accurately for production code even when the library isn't perfect.
472
387
  */
473
388
  if (require('dcp/build').config.build !== 'debug')
474
- nascentWorker.on('end', processExit);
389
+ worker.on('end', processExit);
475
390
  else
476
- nascentWorker.on('end', () => setTimeout(processExit, getCleanupTimeoutMs()).unref());
391
+ worker.on('end', () => setTimeout(processExit, worker.config.cleanupTimeout * 1e3).unref());
477
392
 
478
- if (dcpWorkerOptions.publicGroupFallback)
393
+ if (worker.config.publicGroupFallback)
479
394
  {
480
- if (dcpWorkerOptions.leavePublicGroup)
395
+ if (worker.config.leavePublicGroup)
481
396
  console.warn(' ! Global Group fallback has been requested, but the global group is blocked by local configuration');
482
397
  else
483
398
  {
484
399
  /* Enable global group fallback - this currently works by enabling or disabling the global group
485
400
  * on the next fetch based on whether or not the most recent fetch was an empty task or not.
486
401
  */
487
- nascentWorker.on('fetch', fetchEventHandler);
402
+ worker.on('fetch', fetchEventHandler);
488
403
 
489
404
  function fetchEventHandler(ev)
490
405
  {
491
406
  if (ev instanceof Error)
492
407
  console.error('Error fetching task:', ev);
493
408
  else
494
- dcpWorkerOptions.leavePublicGroup = Boolean(slicesFetched(ev) > 0);
409
+ worker.config.leavePublicGroup = Boolean(slicesFetched(ev) > 0);
495
410
  }
496
411
  }
497
412
  }
@@ -510,25 +425,26 @@ z */
510
425
  return plural;
511
426
  }
512
427
 
513
- if (dcpWorkerOptions.jobAddresses?.length > 0)
514
- bannerLog(` * Processing only ${qty(dcpWorkerOptions.jobAddresses, 'job')} ` + dcpWorkerOptions.jobAddresses.join(', '));
515
- if (dcpWorkerOptions.computeGroups && Object.keys(dcpWorkerOptions.computeGroups).length > 0)
516
- bannerLog(` . Joining compute ${qty(dcpWorkerOptions.computeGroups, 'group')} ` + dcpWorkerOptions.computeGroups.map(el => el.joinKey).join(', '));
517
- if (dcpWorkerOptions.publicGroupFallback)
428
+ if (worker.config.jobAddresses?.length > 0)
429
+ bannerLog(` * Processing only ${qty(worker.config.jobAddresses, 'job')} ` + worker.config.jobAddresses.join(', '));
430
+ if (worker.config.computeGroups && Object.keys(worker.config.computeGroups).length > 0)
431
+ bannerLog(` . Joining compute ${qty(worker.config.computeGroups, 'group')} ` + worker.config.computeGroups.map(el => el.joinKey).join(', '));
432
+ if (worker.config.publicGroupFallback)
518
433
  bannerLog(' . Falling back on global group when preferred groups have no work');
519
- if (dcpWorkerOptions.leavePublicGroup)
434
+ if (worker.config.leavePublicGroup)
520
435
  bannerLog(' . Leaving the global compute group');
521
- bannerLog(` . Configured Cores: { cpu: ${dcpWorkerOptions.cores.cpu}, gpu: ${dcpWorkerOptions.cores.gpu} }`);;
522
- bannerLog(` . Utilization: { cpu: ${dcpWorkerOptions.utilization.cpu}, gpu: ${dcpWorkerOptions.utilization.gpu} }`);
523
- bannerLog(` . Effective Cores: { cpu: ${dcpWorkerOptions.utilization.cpu * dcpWorkerOptions.cores.cpu}, gpu: ${dcpWorkerOptions.utilization.gpu * dcpWorkerOptions.cores.gpu} }`);
524
- bannerLog(` . Maximum Sandboxes: ${dcpWorkerOptions.maxSandboxes}`);
436
+
437
+ bannerLog(` . Configured Cores: { cpu: ${worker.config.cores.cpu}, gpu: ${worker.config.cores.gpu} }`);
438
+ bannerLog(` . Utilization: { cpu: ${worker.config.utilization.cpu}, gpu: ${worker.config.utilization.gpu} }`);
439
+ bannerLog(` . Effective Cores: { cpu: ${worker.config.utilization.cpu * worker.config.cores.cpu}, gpu: ${worker.config.utilization.gpu * worker.config.cores.gpu} }`);
440
+ bannerLog(` . Maximum Sandboxes: ${worker.config.maxSandboxes}`);
525
441
  if (cliArgs.verbose)
526
442
  bannerLog(` + Verbosity level: ${cliArgs.verbose}`);
527
443
  if (telnetd.hasOwnProperty('port'))
528
444
  bannerLog(` ! telnetd listening on port ${telnetd.port}`);
529
445
 
530
446
  let workerInfo;
531
- console.throb('log', ' ! Waiting for dcp-evaluator to start...');
447
+ console.throb('log', ` ! Waiting for dcp-evaluator on ${sawOptions.hostname}:${sawOptions.port} to start...`);
532
448
  for (let i=0; !workerInfo; i++)
533
449
  {
534
450
  workerInfo = await require('../lib/worker-info').getEvaluatorInformation(sawOptions);
@@ -557,20 +473,19 @@ z */
557
473
  for (let descriptor in workerInfo.webgpu.info)
558
474
  bannerLog(` -\t${descriptor}: ${workerInfo.webgpu.info[descriptor]}`);
559
475
  systemStateInfo.gpu = Object.assign({}, workerInfo.webgpu.info);
560
- systemStateInfo.gpu.device
561
- for (let descriptor in bannedGPUs)
476
+ for (let descriptor in worker.config.bannedGPUs)
562
477
  {
563
- if (bannedGPUs[descriptor].test(workerInfo.webgpu.info[descriptor]))
478
+ if (worker.config.bannedGPUs[descriptor].test(workerInfo.webgpu.info[descriptor]))
564
479
  {
565
480
  console.error(' * This GPU is not supported; disabling');
566
- dcpWorkerOptions.cores = { cpu: dcpWorkerOptions.cores.cpu, gpu: 0 };
481
+ worker.config.cores = { cpu: worker.config.cores.cpu, gpu: 0 };
567
482
  systemStateInfo.gpu.disabled = true;
568
483
  break;
569
484
  }
570
485
  }
571
486
  }
572
487
 
573
- bannerLog(' . Supervisor version: ' + nascentWorker.supervisorVersion);
488
+ bannerLog(' . Supervisor version: ' + worker.supervisorVersion);
574
489
  bannerLog(' . Output mode: ' + cliArgs.outputMode);
575
490
 
576
491
  if (parseFloat(cliArgs.reportInterval))
@@ -587,7 +502,6 @@ z */
587
502
  setImmediate(async function workerStart() {
588
503
  bannerLog(' * Ready.\n');
589
504
  require('../lib/check-scheduler-version').check();
590
- worker = nascentWorker;
591
505
  await worker.start();
592
506
  });
593
507
  }
@@ -604,20 +518,20 @@ z */
604
518
  * -u 0.80,0.75 => utilization = { cpu: 0.80, gpu: 0.75 }
605
519
  * -m 5 => maxSandboxes = 5
606
520
  */
607
- function processCoresAndMaxSandboxes (dcpWorkerOptions, cliArgs)
521
+ function processCoresAndMaxSandboxes (workerConfig, cliArgs)
608
522
  {
609
523
  if (typeof cliArgs['maxSandboxes'] !== 'undefined')
610
- dcpWorkerOptions.maxSandboxes = Number(cliArgs['maxSandboxes']);
524
+ workerConfig.maxSandboxes = Number(cliArgs['maxSandboxes']);
611
525
 
612
526
  const parseArg = (which) => {
613
527
  if (cliArgs[which])
614
528
  {
615
- dcpWorkerOptions[which] = {};
529
+ workerConfig[which] = {};
616
530
  const [cpu, gpu] = cliArgs[which].split(',');
617
531
  if (cpu?.length > 0)
618
- dcpWorkerOptions[which].cpu = Number(cpu);
532
+ workerConfig[which].cpu = Number(cpu);
619
533
  if (gpu?.length > 0)
620
- dcpWorkerOptions[which].gpu = Number(gpu);
534
+ workerConfig[which].gpu = Number(gpu);
621
535
  }
622
536
  };
623
537
 
@@ -626,9 +540,9 @@ function processCoresAndMaxSandboxes (dcpWorkerOptions, cliArgs)
626
540
 
627
541
  if (debugging())
628
542
  {
629
- console.debug(`dcp-worker: cores = { cpu: ${dcpWorkerOptions.cores.cpu}, gpu: ${dcpWorkerOptions.cores.gpu} }`);
630
- console.debug('dcp-worker: utilization =', dcpWorkerOptions.utilization);
631
- console.debug('dcp-worker: maxSandboxes =', dcpWorkerOptions.maxSandboxes);
543
+ console.debug(`dcp-worker: cores = { cpu: ${workerConfig.cores.cpu}, gpu: ${workerConfig.cores.gpu} }`);
544
+ console.debug('dcp-worker: utilization =', workerConfig.utilization);
545
+ console.debug('dcp-worker: maxSandboxes =', workerConfig.maxSandboxes);
632
546
  }
633
547
  }
634
548
 
@@ -646,11 +560,16 @@ function logClosing(facility, ...message)
646
560
  * FUTURE: dashboard API should know how to unregister its hook so that we don't have to clobber
647
561
  * it here.
648
562
  */
649
- screen.log(...message);
650
- screen.destroy();
651
- screen = false;
652
- console = new (require('console').Console)(process); // eslint-disable-line no-global-assign
653
- telnetd.reintercept();
563
+
564
+ try
565
+ {
566
+ screen.log(...message);
567
+ screen.destroy();
568
+ screen = false;
569
+ console = new (require('console').Console)(process); // eslint-disable-line no-global-assign
570
+ telnetd.reintercept();
571
+ }
572
+ catch(error) {} // eslint-disable-line no-empty
654
573
  }
655
574
 
656
575
  console[facility](...message);
@@ -668,33 +587,24 @@ function handleUnhandled(error)
668
587
  worker = false;
669
588
 
670
589
  process.exitCode = process.exitCode || EXIT_UNHANDLED;
590
+ logClosing('error', 'trapped unhandled', error);
671
591
 
672
- try
592
+ if (_worker)
673
593
  {
674
- logClosing('error', error);
675
- } catch(e) {} // eslint-disable-line no-empty
676
-
677
- if (!_worker)
678
- console.error('trapped unhandled error:', error)
679
- else
680
- {
681
- console.error('trapped unhandled error -- stopping worker:', error);
594
+ setTimeout(() => {
595
+ logClosing('error', 'handleFatalError timeout - exiting now');
596
+ processExit();
597
+ }, _worker.config.cleanupTimeout * 1e3).unref();
682
598
  _worker.on('end', processExit);
683
599
  _worker.stop();
684
600
  }
685
601
 
686
- setTimeout(() => {
687
- logClosing('error', 'handleFatalError timeout - exiting now');
688
- processExit();
689
- }, getCleanupTimeoutMs()).unref();
690
-
691
- try {
692
- let log = dcpConfig && dcpConfig.worker && dcpConfig.worker.unhandledRejectionLog;
693
- if (!log) log = process.env.DCP_WORKER_UNHANDLED_REJECTION_LOG;
694
- if (log) {
602
+ try
603
+ {
604
+ let log = process.env.DCP_WORKER_UNHANDLED_REJECTION_LOG || worker?.config?.unhandledRejectionLog;
605
+ if (log)
695
606
  fs.appendFileSync(process.env.DCP_WORKER_UNHANDLED_REJECTION_LOG,
696
607
  `${Date.now()}: ${error.message}\n${error.stack}\n\n`);
697
- }
698
608
  } catch(e) {} // eslint-disable-line no-empty
699
609
  }
700
610
 
@@ -813,7 +723,7 @@ function handleSigDeath(signalName, signal)
813
723
  console.warn(`trapped ${signalName}, signal ${signal} -- stopping worker`,
814
724
  immediate ? 'immediately' : `after ${handleSigDeath.count} slices have finished`);
815
725
  worker.stop(immediate);
816
- setTimeout(die, getCleanupTimeoutMs()).unref();
726
+ setTimeout(die, worker.config.cleanupTimeout * 1e3).unref();
817
727
  }
818
728
  process.emit('dcpBeforeExit');
819
729
 
@@ -827,81 +737,6 @@ function handleSigDeath(signalName, signal)
827
737
  }
828
738
  globalThis.die = () => handleSigDeath('QUIT', 15);
829
739
 
830
- /**
831
- * Returns the duration of the cleanup timeout in milliseconds. It is possible to specify zero.
832
- */
833
- function getCleanupTimeoutMs()
834
- {
835
- const defaultCT = 60;
836
- var cleanupTimeout = dcpConfig.worker?.cleanupTimeout;
837
-
838
- if (typeof cleanupTimeout === 'undefined')
839
- cleanupTimeout = defaultCT;
840
- if (typeof cleanupTimeout !== 'number')
841
- cleanupTimeout = Number(cleanupTimeout)
842
- if (isNaN(cleanupTimeout))
843
- {
844
- cleanupTimeout = defaultCT;
845
- if (!getCleanupTimeoutMs.warned)
846
- {
847
- console.error(`warning: dcpConfig.worker.cleanupTimeout is not a number (${dcpConfig.worker.cleanupTimeout})`);
848
- getCleanupTimeoutMs.warned = true;
849
- }
850
- }
851
- return cleanupTimeout * 1000;
852
- }
853
-
854
- /**
855
- * Ensure the default configuration hasn't been modified by the end-user-sysadmin. It is an
856
- * attractive nuisance, as it looks just like the file they should modify, but if they make
857
- * security changes there that are overwritten in an subsequent update, it will be a problem.
858
- *
859
- * Every time a new package is generated, the default config file has its md5 checksum recorded
860
- * via the pack npm hook; all we do is make sure it hasn't changed.
861
- */
862
- function verifyDefaultConfigIntegrity()
863
- {
864
- const workerConfPath = require('dcp-client').__cn;
865
- const md5sumPath = workerConfPath + '.md5';
866
-
867
- if (!fs.existsSync(md5sumPath))
868
- {
869
- console.error(chalk.bold.red(` ! warning: ${md5sumPath} not found; cannot verify configuration integrity`));
870
- require('dcp/utils').sleep(2);
871
- }
872
- else
873
- {
874
- const originalMd5sum = fs.readFileSync(md5sumPath, 'ascii');
875
- const actualMd5sum = crypto.createHash('md5')
876
- .update(fs.readFileSync(workerConfPath))
877
- .digest('hex');
878
-
879
- if (!originalMd5sum.startsWith(actualMd5sum))
880
- {
881
- console.warn(chalk.yellow(` ! Detected modified ${workerConfPath};`));
882
- console.warn(' ! DCP Worker configuration changes should not be made by updating the default');
883
- console.warn(' config, as that file will be overwritten on the next npm update. Instead,');
884
- console.warn(' make changes via one of the following locations:');
885
- console.warn(' - ~/.dcp/dcp-worker/dcp-config.js');
886
- console.warn(' - /etc/dcp/dcp-worker/dcp-config.js');
887
- console.warn(' - /etc/override/dcp/dcp-worker/dcp-config.js');
888
- console.warn(' - the Windows Registry');
889
-
890
- if (require('dcp/build').config.build !== 'debug')
891
- processExit(1);
892
-
893
- console.log(chalk.bold.red.inverse("If this wasn't a debug build, the worker would exit now."));
894
- require('dcp/utils').sleep(2);
895
- }
896
- }
897
-
898
- if (dcpConfig.cookie !== process.env.DCP_CONFIG_COOKIE || !dcpConfig.cookie)
899
- {
900
- console.error(' ! DCP Worker default configuration was not loaded; exiting.');
901
- processExit(1);
902
- }
903
- }
904
-
905
740
  /**
906
741
  * Cast b to boolean such that 'false' becomes false, falsey things become false, and everything else
907
742
  * becomes true.
@@ -1,8 +1,9 @@
1
1
  /**
2
- * @file dcp-worker-config.js - Default configuration for the DCP Worker.
3
- * Copy this file before modifying, so that changes are preserved during the upgrade cycle.
2
+ * @file dcp-config.js - Sample configuration for the DCP Worker.
3
+ *
4
4
  * Remove (or comment out) settings you don't need to change, so that changes to the
5
- * defaults can be made during an upgrade. Suggested locations include:
5
+ * defaults can be made during an upgrade. The standard dcp-client path options apply;
6
+ * Suggested locations include:
6
7
  * - /etc/dcp/dcp-worker/dcp-config.js, or
7
8
  * - ~/.dcp/dcp-worker/dcp-config.js.
8
9
  *
@@ -40,17 +41,20 @@
40
41
  'in': 0, /* DCC per megabyte of inbound network traffic */
41
42
  'out': 0, /* DCC per megabyte of outbound network traffic */
42
43
  },
44
+
45
+ /* Regexps of GPUs we cannot use. Properties match device descriptors. */
43
46
  bannedGPUs: {
44
- description: /D3D.*version\s[0-2][0-9]/
47
+ description: /D3D.*version\s[0-2][0-9]/,
48
+ device: /llvmpipe/,
45
49
  },
46
50
 
47
51
  /* Extra Compute Groups this worker can participate in. Join credentials are supplied by
48
52
  * Distributive and/or local IT staff at site-licensed locations.
49
53
  */
50
54
  computeGroups: [
51
- // { joinKey: 'scott', joinSecret: 'tiger' },
52
- // { joinKey: 'scott', joinHash: 'eh1-672937c2b944982e071185b888770f8b8ea67c11f56d545e403e0d513c609b87' },
53
- // keystore('~/.dcp/scott'),
55
+ { joinKey: 'scott', joinSecret: 'tiger' },
56
+ { joinKey: 'scott', joinHash: 'eh1-672937c2b944982e071185b888770f8b8ea67c11f56d545e403e0d513c609b87' },
57
+ { keystore('~/.dcp/scott') },
54
58
  ],
55
59
  },
56
60
 
@@ -61,6 +65,4 @@
61
65
  evaluator: {
62
66
  listen: new URL('dcpsaw://localhost:9000/'),
63
67
  },
64
-
65
- cookie: require('process').env.DCP_CONFIG_COOKIE, /* Used to verify that this file was loaded. */
66
68
  }
@@ -135,7 +135,7 @@ exports.init = function dashboard$$init(worker, options, bannerLogCumulative)
135
135
  function updateWorkerInfo(fetchInfo)
136
136
  {
137
137
  var gpuInfo = '';
138
- const workerOptions = worker.workerOptions;
138
+
139
139
  if (fetchInfo)
140
140
  lastTask = fetchInfo;
141
141
 
@@ -162,10 +162,10 @@ exports.init = function dashboard$$init(worker, options, bannerLogCumulative)
162
162
  ` Bank Account: ${chalk.yellow(worker.paymentAddress || 'Starting...')}`,
163
163
  ` Identity: ${chalk.yellow(worker.identityKeystore? worker.identityKeystore.address : 'Starting...')}`,
164
164
  ` GPU: ${gpuInfo}`,
165
- ` Jobs: ${workerOptions.jobAddresses?.length ? workerOptions.jobAddresses.join(', ') : '<any>'}`,
166
- ` Compute Groups: ${Object.keys(workerOptions.computeGroups).length + (workerOptions.leavePublicGroup ? 0 : 1)}`,
167
- `Global Compute Group: ${workerOptions.leavePublicGroup ? 'no' : 'yes'}`,
168
- ` Worker Id: ${worker.workerId}`,
165
+ ` Jobs: ${worker.config.jobAddresses?.length ? worker.config.jobAddresses.join(', ') : '<any>'}`,
166
+ ` Compute Groups: ${Object.keys(worker.config.computeGroups).length + (worker.config.leavePublicGroup ? 0 : 1)}`,
167
+ `Global Compute Group: ${worker.config.leavePublicGroup ? 'no' : 'yes'}`,
168
+ ` Worker Id: ${worker.id}`,
169
169
  ` Current Time: ${new Date(Date.now()).toUTCString()}`,
170
170
  ` Last Task Request: ${lastTask ? new Date(lastTask.fetchStart).toUTCString() : 0}`,
171
171
  ` Slices in task: ${lastTask ? Object.values(lastTask.slices).reduce((acc, val) => acc + val, 0) : 0}`,
@@ -7,6 +7,7 @@
7
7
  'use strict';
8
8
 
9
9
  const process = require('process');
10
+ const usingDebugger = require('module')._cache.niim instanceof require('module').Module;
10
11
 
11
12
  /**
12
13
  * Initialize the console logger
@@ -56,14 +57,14 @@ exports.init = function console$$init(options)
56
57
 
57
58
  if (throbArgsCache)
58
59
  {
59
- if (stream.isTTY)
60
+ if (stream.isTTY && !usingDebugger)
60
61
  stream.write(throbArgsCache.args.join(' '));
61
62
  else
62
63
  console[throbArgsCache.throbFacility](...throbArgsCache.args);
63
64
  throbArgsCache = false;
64
65
  }
65
66
 
66
- if (stream.isTTY)
67
+ if (stream.isTTY && !usingDebugger)
67
68
  {
68
69
  i = (i + 1) % throbChars.length;
69
70
  stream.write(throbChars[i] + '\u0008');
@@ -70,6 +70,7 @@ exports.init = function dashboardLogger$$init(options)
70
70
  }
71
71
 
72
72
  throbPos = (throbPos + 1) % throbChars.length;
73
- dashboardTui.logPane.advanceThrob(throbChars[throbPos]);
73
+ if (dashboardTui.logPane?.advanceThrob)
74
+ dashboardTui.logPane.advanceThrob(throbChars[throbPos]);
74
75
  }
75
76
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dcp-worker",
3
- "version": "3.3.19",
3
+ "version": "4.0.1",
4
4
  "description": "Node.js Worker for Distributive Compute Platform",
5
5
  "main": "bin/dcp-worker",
6
6
  "keywords": [
@@ -23,7 +23,7 @@
23
23
  },
24
24
  "directories": {
25
25
  "lib": "lib",
26
- "etc": "etc"
26
+ "examples": "examples"
27
27
  },
28
28
  "scripts": {
29
29
  "check": "trunk check",
@@ -32,7 +32,6 @@
32
32
  "hook": "PATH=npm-hooks:$PATH &&",
33
33
  "lint": "eslint --cache --cache-strategy=content --cache-location=.cache/eslint/ --ignore-path=.gitignore --ext=js .",
34
34
  "test": "peter tests",
35
- "prepack": "node npm-hooks/prepack",
36
35
  "postpublish": "npm-hooks/postpublish",
37
36
  "prepublishOnly": "npm-hooks/prepublish"
38
37
  },
@@ -40,7 +39,7 @@
40
39
  "blessed": "^0.1.81",
41
40
  "blessed-contrib": "4.11.0",
42
41
  "chalk": "^4.1.0",
43
- "dcp-client": "^4.4.24",
42
+ "dcp-client": "^4.4.28",
44
43
  "kvin": "^1.2.7",
45
44
  "posix-getopt": "^1.2.1",
46
45
  "semver": "^7.3.8",
@@ -1,2 +0,0 @@
1
- 271fe64e9b77126815dbb9aff6a3412f
2
- ### DO NOT MODIFY THIS FILE!!! ###
package/npm-hooks/prepack DELETED
@@ -1,21 +0,0 @@
1
- #! /usr/bin/env node
2
- /**
3
- * @file prepack
4
- * Hook which generates the config md5 on pack (or publish)
5
- * @author Wes Garland, wes@distributive.network
6
- * @date April 2023, June 2023
7
- */
8
-
9
- const fs = require('fs');
10
- const process = require('process');
11
- const path = require('path');
12
-
13
- function md5(content)
14
- {
15
- return require('crypto').createHash('md5').update(content).digest('hex');
16
- }
17
-
18
- process.chdir(path.resolve(__dirname, '..'));
19
- fs.writeFileSync('etc/dcp-worker-config.js.md5', ''
20
- + `${md5(fs.readFileSync('etc/dcp-worker-config.js'))}\n`
21
- + '### DO NOT MODIFY THIS FILE!!! ###\n');