dcp-worker 4.5.3 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.gitlab-ci.yml CHANGED
@@ -8,6 +8,11 @@ variables:
8
8
  npm_config_cache: '.cache/npm/'
9
9
  npm_config_prefer_offline: 'true'
10
10
  npm_config_fund: 'false'
11
+ # DCP_BUILD variables only apply when using a gitlab-hosted dcp-client
12
+ DCP_BUILD: debug
13
+ DCP_BUILD_BRANCH: develop
14
+ DCP_BUILD_HOST: 'http://dcp-client-srv.office.distributive.network'
15
+ DCP_CLIENT_GITLAB: 'gitlab:Distributed-Compute-Protocol/dcp-client#'
11
16
 
12
17
  default:
13
18
  # Use in-house GitLab runners.
@@ -28,6 +33,8 @@ workflow:
28
33
  # Only run branch pipelines for `develop`, or merge request pipelines.
29
34
  - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
30
35
  - if: $CI_PIPELINE_SOURCE == "merge_request_event"
36
+ # Allow manually running a branch pipeline without opening an MR first.
37
+ - if: $CI_PIPELINE_SOURCE == "web" || $CI_PIPELINE_SOURCE == "api"
31
38
 
32
39
  stages:
33
40
  - build
@@ -40,6 +47,12 @@ build:
40
47
  stage: build
41
48
  script:
42
49
  - npm clean-install
50
+ - DCP_CLIENT_VERSION=`node -p "require('./package.json').dependencies['dcp-client']"`
51
+ - DCP_CLIENT_ORIGIN=`printf "${DCP_CLIENT_GITLAB}"`
52
+ - |
53
+ [[ "${DCP_CLIENT_VERSION}" == "gitlab:"* ]] &&
54
+ wget "${DCP_BUILD_HOST}/?dcpClient=${DCP_CLIENT_VERSION//$DCP_CLIENT_ORIGIN/}&build=${DCP_BUILD}" -O node_modules/dcp-client/dist/dcp-client-bundle.js
55
+ - echo "Done" # Because CI will error if the last command returns with a non-zero exit code... and the above will be unless a specific dcp-client version is required
43
56
  cache:
44
57
  - key:
45
58
  prefix: $CI_JOB_NAME_SLUG
package/README.md CHANGED
@@ -156,7 +156,7 @@ A Node.js daemon which
156
156
  A Node.js daemon which
157
157
  * manages a ledger for DCC. This is not a blockchain currency.
158
158
  * enables the movement of DCC between entities requesting work and entities performing work
159
- * enables the movement of DCC between the ledger and the blockchain
159
+ * enables the movement of DCC between the ledger and Paypal
160
160
  * enables the placement of DCC in escrow on behalf of the Scheduler for work which is anticipated to be done
161
161
 
162
162
  #### Compute Group
@@ -167,7 +167,7 @@ A user-facing web application which allows or enables
167
167
  * creation and management of user accounts
168
168
  * management of bank accounts (ledgers)
169
169
  * transfer of DCC between bank accounts
170
- * transfer of DCC to and from the blockchain
170
+ * transfer of DCC to and from USD
171
171
  * execution of the browser-based Worker
172
172
 
173
173
  #### Worker
@@ -209,7 +209,7 @@ A group of related modules
209
209
  A parallel supercomputer consisting of one or more schedulers and workers. When used as a proper noun, the distributed computer being discussed is the one hosted at https://portal.distributed.computer/
210
210
 
211
211
  #### Bank Account
212
- A ledger which acts a repository for DCC which is not on the block chain. The Bank can move DCC between Bank Accounts much more quickly than it can move DCC between Addresses on the Ethereum block chain network. Meta data attached to bank accounts can restrict certain operations, such as ear-marking funds for use only by job deployment.
212
+ A ledger which acts a repository for DCC which is not on the block chain. Meta data attached to bank accounts can restrict certain operations, such as ear-marking funds for use only by job deployment.
213
213
 
214
214
  #### Address
215
215
  A unique identifier in DCP which can be used to identity a bank account, user, compute group, etc.
package/bin/dcp-worker CHANGED
@@ -644,6 +644,9 @@ async function main()
644
644
  if (loggingOptions.verbose)
645
645
  console.info(` + Verbosity level: ${loggingOptions.verbose}`);
646
646
 
647
+ if (worker.config.pidfile && require('../lib/pidfile').write(worker.config.pidfile) !== true)
648
+ await cleanupThenExit(exitCodes.pidConflict);
649
+
647
650
  /* Poll the evaluator forever until it accepts a connection */
648
651
  let evaluatorInfo = false;
649
652
  let p$throbSleep;
@@ -665,7 +668,7 @@ async function main()
665
668
  utils.noteWorkerStart(worker);
666
669
  if (performance.now() - ts > 100)
667
670
  console.throb();
668
- p$throbSleep = a$sleep(Math.max(i + 1, 10) / 4);
671
+ p$throbSleep = a$sleep(Math.min(i + 1, 30) / 4);
669
672
  await p$throbSleep;
670
673
  console.throb();
671
674
  }
@@ -807,9 +810,6 @@ async function main()
807
810
  }
808
811
  });
809
812
 
810
- if (worker.config.pidfile && require('../lib/pidfile').write(worker.config.pidfile) !== true)
811
- await cleanupThenExit(exitCodes.pidConflict);
812
-
813
813
  if (worker.config.claimEarnings === false && !worker.config.unmanaged)
814
814
  {
815
815
  const amount = await DistributiveWorker.checkUnclaimedEarnings();
@@ -934,7 +934,7 @@ async function cleanupThenExit(exitCode)
934
934
  worker.stop(true); /* toggle internal worker state so it won't surprise us by starting sandboxes */
935
935
  }
936
936
 
937
- console.warn(' ! begin shutdown, exit code =', exitCode);
937
+ console.warn(' ! shutdown, exit code =', exitCode);
938
938
  const p$workerShutdownTasks = Promise.all([
939
939
  require('../lib/p2p-shared').shutdown(),
940
940
  utils.noteWorkerShutdown(worker),
package/lib/p2p-shared.js CHANGED
@@ -16,8 +16,9 @@ const debug = require('debug');
16
16
  const assert = require('assert');
17
17
  const wallet = require('dcp/wallet');
18
18
 
19
- const { a$sleep } = require('dcp/utils');
20
- const { DcpURL } = require('dcp/dcp-url');
19
+ const { DistributiveWorker } = require('dcp/worker');
20
+ const { a$sleep } = require('dcp/utils');
21
+ const { DcpURL } = require('dcp/dcp-url');
21
22
 
22
23
  const version = '1.0.0';
23
24
  var worker; /* singleton instance of DistributiveWorker - held even after stop */
@@ -80,6 +81,11 @@ exports.shutdown = async function shutdown()
80
81
  await p2p.cleanupForExit();
81
82
  }
82
83
 
84
+ /**
85
+ * Send an announcement to the worker. This carries ad-hoc information about changes in the internal
86
+ * worker state. Many elements in the UI are affected by the announcement via worker-announce-*
87
+ * attributes.
88
+ */
83
89
  function announce(announcement, details)
84
90
  {
85
91
  debug('dcp-worker:p2p')('sending anouncement', announcement);
@@ -94,7 +100,7 @@ function announce(announcement, details)
94
100
  }
95
101
 
96
102
  if (!exports.disabled)
97
- p2p.sendMessage(`worker-${workerId}-announce`, { announce: announcement, version }, owner);
103
+ p2p.sendMessage(`worker-${workerId}-announce`, { announce: announcement, version, details }, owner);
98
104
  }
99
105
 
100
106
  function enqRespond(message, details)
@@ -182,6 +188,72 @@ function pauseWorker()
182
188
  return p$pause;
183
189
  }
184
190
 
191
+ /**
192
+ * Replace an existing configuration value, coercing value as necessary.
193
+ * @param {string} path path within worker.config to the current value, eg utilization.cpu
194
+ * @param {string} value the new value
195
+ */
196
+ function replaceConfigValue(path, value)
197
+ {
198
+ var node = worker.config;
199
+ var components = path.split('.');
200
+ var component;
201
+
202
+ if (!/^([a-z][A-Za-z0-9_.]+)+$/.test(path))
203
+ throw new Error(`invalid config path: ${path}`);
204
+
205
+ while((component = components.shift()))
206
+ {
207
+ if (components.length === 0)
208
+ break;
209
+ if (!node[component])
210
+ {
211
+ console.error(`Invalid property ${component} in ${path}`);
212
+ return;
213
+ }
214
+ node = node[component];
215
+ }
216
+
217
+ switch(typeof node[component])
218
+ {
219
+ case 'object':
220
+ if (node[component] === null)
221
+ {
222
+ console.error(`cannot replace null value at ${path}`);
223
+ break;
224
+ }
225
+ /* fallthrough */
226
+ default:
227
+ console.error(`cannot replace ${typeof node[component]} at ${path}`);
228
+ break;
229
+ case 'number':
230
+ value = value.trim();
231
+ if (value.endsWith('%'))
232
+ value = parseInt(value, 10) / 100;
233
+ replaceWith(Number(value));
234
+ break;
235
+ case 'boolean':
236
+ switch(value)
237
+ {
238
+ case 'true': replaceWith(true); break;
239
+ case 'false': replaceWith(false); break;
240
+ default:
241
+ console.error(`cannot replace boolean component at ${path} with ${value}`);
242
+ break;
243
+ }
244
+ break;
245
+ case 'string':
246
+ replaceWith(value)
247
+ break;
248
+ }
249
+
250
+ function replaceWith(newValue)
251
+ {
252
+ console.info(`worker.config.${path}: ${node[component]} => ${newValue}`);
253
+ node[component] = newValue;
254
+ }
255
+ }
256
+
185
257
  /**
186
258
  * Handle a control message, eg from the portal. Control messages are sent on channel worker-ID and
187
259
  * tell the worker what to do, eg enable logs, reboot, change configuration, etc. These are always
@@ -222,18 +294,13 @@ function handleControlMessage(message, channel, sender, originator)
222
294
  console.info(' . Unpausing worker');
223
295
  break;
224
296
  case 'stop':
297
+ console.info(' . Remote peer requested worker stop');
225
298
  worker.stop(message.arguments?.[0]); /* announcement comes from worker<stop> */
226
299
  break;
227
300
  case 'halt':
228
301
  throw new Error(`halt (p2p ${message.sender})`);
229
- case 'set-cores':
230
- Object.assign(worker.config.cores, message.arguments[0]);
231
- worker.dropSandboxes();
232
- console.info(' . Set cores:', worker.config.cores);
233
- break;
234
- case 'set-max-sandboxes':
235
- worker.config.maxSandboxes = Number(message.arguments[0]);
236
- console.info(' . Set max sandboxes:', worker.config.maxSandboxes);
302
+ case 'replace-config-value':
303
+ replaceConfigValue.apply(null, message.arguments);
237
304
  break;
238
305
  case 'update-runinfo':
239
306
  worker.updateRunInfo();
@@ -264,6 +331,26 @@ function handleControlMessage(message, channel, sender, originator)
264
331
  }).finally(() => worker.stop(true));
265
332
  break;
266
333
  }
334
+ case 'claim':
335
+ {
336
+ const earningsAccount = new wallet.Address(message.arguments[0]);
337
+ DistributiveWorker.transferUnclaimedEarnings(earningsAccount).then(res => {
338
+ if (res.payload)
339
+ {
340
+ console.log(` ! Claimed ${res.payload} ⊇ for ${earningsAccount}`);
341
+ announce('alert', `Moved ${res.payload} ⊇ into account ${earningsAccount.toShortString()}`);
342
+ }
343
+ });
344
+ }
345
+ /* fallthrough */
346
+ case 'set-earnings-account':
347
+ {
348
+ const newAccount = new wallet.Address(message.arguments[0]);
349
+ worker.config.paymentAddress = newAccount;
350
+ console.info(` . Set earnings account: ${worker.config.paymentAddress}`);
351
+ announce('earnings-account', String(worker.config.paymentAddress));
352
+ break;
353
+ }
267
354
  case 'enq':
268
355
  handleEnquireMessage(message, channel, sender, originator);
269
356
  break;
package/lib/show.js CHANGED
@@ -36,7 +36,7 @@ async function show(worker, mode)
36
36
  case 'identity':
37
37
  return identity.get().address;
38
38
  case 'owner':
39
- return await require('./utils').getOwner(worker) || 'worker is not registered';
39
+ return String(await require('./utils').getOwner(worker)) || 'worker is not registered';
40
40
  case 'earnings-account':
41
41
  return false
42
42
  || (worker.config.paymentAddress && String(worker.config.paymentAddress))
@@ -72,18 +72,15 @@ async function eval$$getInfo()
72
72
  */
73
73
  function getEvaluatorInformation(evaluatorConfig)
74
74
  {
75
+ if (!getEvaluatorInformation.seq)
76
+ getEvaluatorInformation.seq = 0;
77
+ const seq = ++getEvaluatorInformation.seq;
75
78
  const StandaloneWorker = require('dcp-client/lib/standaloneWorker').workerFactory(evaluatorConfig);
76
- const evaluatorHandle = new StandaloneWorker({ name: 'DCP Sandbox #1', });
77
- var resolve, reject;
78
- const p$workerInfo = new Promise((res, rej) => {
79
- resolve = res;
80
- reject = rej;
81
- }).finally(() => {
82
- evaluatorHandle.terminate();
83
- evaluatorHandle.removeAllListeners();
84
- });
85
- evaluatorHandle.addEventListener('end', () => resolve(false));
86
- evaluatorHandle.addEventListener('error', reject);
79
+ const evaluatorHandle = new StandaloneWorker({ name: `DCP Probe Sandbox #${seq}` });
80
+ const pr$workerInfo = Promise.withResolvers();
81
+
82
+ evaluatorHandle.addEventListener('end', () => pr$workerInfo.resolve(false));
83
+ evaluatorHandle.addEventListener('error', pr$workerInfo.reject);
87
84
  evaluatorHandle.ref();
88
85
 
89
86
  evaluatorHandle.onmessage = function onmessage(__event)
@@ -94,18 +91,29 @@ function getEvaluatorInformation(evaluatorConfig)
94
91
  {
95
92
  const workerInfo = reply.data;
96
93
  if (typeof workerInfo !== 'object' || !workerInfo.worktimes || !workerInfo.webgpu)
97
- throw new Error(`malformed response from evaluator`);
98
- resolve(workerInfo);
94
+ throw new Error('malformed response from evaluator');
95
+ pr$workerInfo.resolve(workerInfo);
99
96
  }
100
97
  }
101
98
 
99
+ const timerId = setTimeout(() => {
100
+ pr$workerInfo.resolve(false);
101
+ }, 5000); /* 5000ms is about 4800ms more than this should take even on a busy machine. */
102
+
102
103
  const message = {
103
104
  request: 'eval',
104
105
  data: '(' + eval$$getInfo.toString() + ')()',
105
106
  msgId: evaluatorId,
106
107
  }
108
+
109
+ pr$workerInfo.promise.finally(() => {
110
+ evaluatorHandle.terminate();
111
+ evaluatorHandle.removeAllListeners();
112
+ clearTimeout(timerId);
113
+ });
114
+
107
115
  evaluatorHandle.postMessage(StandaloneWorker.encodeMessage(message));
108
- return p$workerInfo;
116
+ return pr$workerInfo.promise;
109
117
  }
110
118
 
111
119
  exports.getEvaluatorInformation = getEvaluatorInformation;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dcp-worker",
3
- "version": "4.5.3",
3
+ "version": "4.6.0",
4
4
  "description": "Node.js Worker for Distributive Compute Platform",
5
5
  "main": "bin/dcp-worker",
6
6
  "keywords": [
@@ -39,7 +39,7 @@
39
39
  "blessed": "0.1.81",
40
40
  "blessed-contrib": "4.11.0",
41
41
  "chalk": "4.1.2",
42
- "dcp-client": "^5.7.5",
42
+ "dcp-client": "gitlab:Distributed-Compute-Protocol/dcp-client#feature/worker-management3",
43
43
  "kvin": "9.1.0",
44
44
  "mux-net": "github:wesgarland/mux-net#e7f81800db4a84ec880026596f7ee68549a6d0f5",
45
45
  "posix-getopt": "1.2.1",
@@ -191,6 +191,9 @@ async function init()
191
191
  logger(`[worker.warning] ${JSON.stringify(warn, null, 2)}`);
192
192
  });
193
193
 
194
+ worker.on("connect", () => {
195
+ logger('Connected to worker, listening for events');
196
+ });
194
197
  }
195
198
 
196
199
  const logLines = [];