Worker API

This API is used to instantiate DCP workers, which will perform compute tasks on the network in exchange for DCCs.

Record of Issue

Date

Authors

Rev

Change

Jul 29 2026

(docs)

2.0.0

Documents DistributiveWorker (“Worker API 2.0”) as the primary class; Worker (“1.0”) remains available as a compatibility wrapper.

May 20 2020

Ryan Rossiter

1.0.0

Initial Worker API impl

dcp/worker exports two classes: DistributiveWorker, the primary class described in this document, and Worker, a deprecated compatibility wrapper around it for existing code – see Worker API 1.0 compatibility, below. New code should use DistributiveWorker.

Glossary

  • Worker - The Worker is an entity representing a supervisor and any number of sandboxes. It connects to the distributed computer and performs work by assigning slices to sandboxes.

  • Supervisor - The supervisor is the entity responsible for managing sandboxes within the worker.

  • Sandbox - A sandbox is the environment in which a slice is computed. The supervisor instantiates and terminates these sandboxes, and assigns it work to be computed. A sandbox could be a web worker, a standalone V8 environment, or any other interface that implements the WebWorker spec.

Worker Class

The Worker class is an EventEmitter instance, and it emits events that can be listened to with the standard EventEmitter methods. See Events for the events it emits.

Constructor

new DistributiveWorker(config: object, SandboxConstructor?: constructor)

Neither argument is required to be present (the constructor tolerates config being omitted), but SandboxConstructor must be resolvable somehow: outside the browser, the constructor throws 'SandboxConstructor not specified for DistributiveWorker!' if it’s omitted and can’t be defaulted. In a browser, it defaults to ./evaluatorsBrowserEvaluator when omitted.

There is no identityKeystore constructor argument or option. The identity used to sign scheduler communications comes from the ambient identity (wallet.getId(), i.e. whatever dcp/identity currently considers the active/default identity for the process).

config: object (also available afterward as worker.config):

  • paymentAddress: Address: Address used for depositing DCCs in after a slice is computed. Coerced from a string automatically the first time worker.configure() runs (called internally by start()); throws if the result isn’t an instance of wallet.Address. When omitted, resolved automatically via the worker-management backend (obtainUnclaimedEarningsPaymentAddress()).

  • jobIds: string[] | false: When an Array, this worker will only compute slices for the listed jobs. Defaults to false (no restriction).

  • computeGroups: object[]: Compute Groups this worker should join, in the same shape as job.computeGroups (see: Compute API).

  • leavePublicGroup: boolean: When true, this worker will not do work for the public Compute Group; it will only accept work from the groups listed in computeGroups.

  • maxSandboxes: number: Maximum number of sandboxes that can be working at one time. When omitted, defaults to a value derived from system memory (roughly one sandbox per 2.5 GB of RAM on Node.js, or navigator.deviceMemory / 2.5 in a browser that exposes it), falling back to 1/2 where that information isn’t available (see DistributiveWorker.recommended.maxSandboxes, a static getter that computes this same value).

  • utilization: { cpu: number, gpu: number }: Proportion (0 < n <= 1) of cores this worker will actually use. Defaults to { cpu: 1.0, gpu: 0.75 }. worker.effectiveCores is cores scaled by this value (see Properties).

  • cores: { cpu: number, gpu: number }: How many CPU/GPU cores this machine has, for the purposes of scheduling. cpu defaults to a live-updating count derived from config.hardware.vCores; setting it explicitly (including to 0, which disables the worker for that resource type) stops it tracking hardware changes until unset again. gpu defaults to 1.

  • hardware: { vCores: number }: Override for the detected logical core count that cores.cpu’s default is derived from.

  • bannedGPUs: object[]: Regexp-keyed device descriptors (matching properties like description/device) identifying GPUs this worker should refuse to use, regardless of cores.gpu/utilization.gpu.

  • minimumWage: { CPU: number, GPU: number, in: number, out: number }: The minimum payout per slice the worker will accept from a job, expressed per unit of each resource:

    • CPU: DCC per second of CPU time.

    • GPU: DCC per second of GPU time.

    • in: DCC per byte of inbound network traffic, that includes the bytes of slice input, arguments, work function, and modules.

    • out: DCC per byte of outbound network traffic, that includes the bytes of console messages and results.

    All four default to 0 when minimumWage (or the whole options object) is omitted.

    Note

    This object is forwarded to the scheduler as-is (as part of the fetch-task request); dcp-client itself does not interpret its units, so the worth calculation happens scheduler-side.

  • schedulerConfig: object: A fragment merged over dcpConfig.scheduler (see leafMerge) for this worker only; use { location: url } to point this worker at a different scheduler than the rest of the application.

  • trustScheduler: boolean: When true (the default), the scheduler is allowed to push configuration changes down to this worker.

  • managed: boolean / unmanaged: boolean / claimedEarnings: boolean: Control the new worker-management integration (registration, run-info/task-info telemetry, unclaimed-earnings transfer) that now runs automatically during start()/stop() – see the claim, metrics, and drop-slice events, below. Setting config.unmanaged truthy skips the management bookkeeping entirely during shutdown.

  • allowConsoleAccess: boolean: When true, work functions running in this worker’s sandboxes may use the sandbox’s native console object directly, in addition to the usual console events.

  • trustComputeGroupOrigins: boolean / allowOrigins: { any, fetchData, fetchWorkFunctions, fetchArguments, sendResults: string[] }: Control which origins this worker will fetch data, work functions, arguments, and modules from, and send results to.

  • watchdogInterval: number | string: How often (accepts ms-style strings, e.g. '7s') the worker checks on its sandboxes’ health. Defaults to dcpConfig.supervisor.tuning.watchdogInterval or 7 seconds.

  • sandboxOptions: object:

    • SandboxConstructor: constructor: Constructor for the sandbox environment, it should implement the WebWorker API. When not provided in the browser, it will default to the global Worker constructor.

    • ignoreNoProgress: boolean = false: When true, the sandbox will ignore errors from the sandbox not firing progress events.

Worker API 1.0 compatibility

For existing code, new Worker(identityKeystore, config) is also available: it constructs a DistributiveWorker(config, config?.sandboxOptions?.SandboxConstructor) and returns a Proxy over it that also answers to a few legacy property names (workerOptions, workerId, paymentAddress, identityKeystore). New code should construct DistributiveWorker directly; using Worker logs a one-time console warning to that effect.

Note

The identityKeystore argument is vestigial: there is no supported way to run a worker under an identity other than the process’s own ambient one. If provided, it is compared (asynchronously, via wallet.getId()) against the ambient identity; a mismatch makes the proxy throw 'ad-hoc identity specification not supported in DCP Worker polyfill' on every subsequent property get/set.

Methods

worker.start(): Promise<void>

This method will start the worker. It will begin to fetch work from the supervisor and submit the computed results automatically. It does not throw if the worker is already started – it silently no-ops instead.

Immediately before starting, a cancelable beforeStart event is emitted (see Events, below); if any listener calls the provided callback, start() returns without starting the worker.

If the worker was disabled via Worker.disableWorker(), calling start() prompts the user (via confirmPrompt) to confirm they want to re-enable and start it, rather than starting immediately.

worker.stop(forceTerminate: boolean = false): Promise<void>

This method will stop the worker. If forceTerminate is true, the worker will terminate all working sandboxes without waiting for them to finish working; otherwise it waits for in-progress slices to complete first.

A cancelable stop event is emitted immediately (see Events, below); if any listener calls the provided callback, the stop is escalated to forceTerminate: true, regardless of what was originally requested. An end event fires once the worker (and schedMsg) have fully stopped.

Worker.disableWorker()

This static method sets a key in local storage (or the equivalent persistent store on Node) to disable the worker. The user will need to manually intervene (or call start(), which will prompt them) before the worker can be started again.

Other methods

The following methods exist and are used internally by the SchedMsg command handlers (below), but are otherwise lightly documented:

  • worker.pause() / worker.unpause(): While paused, the worker will not execute new slices, fetch new work, or return slices to the scheduler.

  • worker.controlledStop(timeLimit: number = 86400 * 1000): Promise<void>: Calls stop(false), but forces stop(true) after timeLimit milliseconds if the graceful stop hasn’t completed by then.

  • worker.returnSandbox(sandbox: Sandbox): Removes a sandbox from the supervisor and terminates it.

  • worker.returnSlice(slice: Slice, reason: string = 'unknown'): Removes a slice from the supervisor and returns it to the scheduler.

  • worker.ref() / worker.unref(): Control whether the worker holds the process/event-loop open while working (Node.js).

Properties

  • worker.working: boolean: This boolean indicates the current status of the worker. It should not be set manually.

  • worker.schedMsg: SchedMsg: The internal schedMsg client instance. Custom behaviour for schedMsg commands can be provided on this object, see Overriding SchedMsg Handlers.

  • worker.config: object: The same config object passed to the constructor (with defaults filled in); mutating it affects the running worker.

  • worker.paymentAddress: Address: Convenience accessor for config.paymentAddress – prefer setting config.paymentAddress directly.

  • worker.id: opaqueId (get/set): An opaque identifier for this worker. The getter is lazy: the first read (if nothing has been set yet) fetches a persisted id from local storage, generating and persisting a new one if none exists. Setting it directly (worker.id = '...') does not persist the value – it only affects the in-memory instance.

    Note

    Through the deprecated Worker 1.0 proxy, worker.workerId is effectively read-only: the getter forwards to id, but the setter does not, so worker.workerId = x has no effect. Use worker.id = x, or construct DistributiveWorker directly.

  • worker.sandboxes: Sandbox[] / worker.workingSandboxes: Sandbox[]: All non-terminated sandboxes, and the subset of those currently executing a slice, respectively. These are the internal Sandbox objects, distinct from the SandboxHandle objects handed to sandbox event listeners – see Sandbox API, below.

  • worker.slices: Slice[] / worker.queuedSlices: Slice[] / worker.workingSlices: Slice[]: All slices currently known to the worker, and the queued/working subsets thereof.

  • worker.effectiveCores: { cpu: number, gpu: number }: config.cores, scaled by config.utilization.

  • worker.originManager: OriginAccessManager: Enforces the allowOrigins/trustComputeGroupOrigins options.

  • worker.supervisorVersion: string: Version string of the internal Supervisor implementation.

Note

There is no worker.supervisor property. The closest equivalent is worker.badSupervisorBackdoor, which the source explicitly documents as @deprecated - Please do not use this. The properties above cover the supported ways to interact with the supervisor from outside the Worker class.

Events

  • start: Emitted when the worker is started.

  • beforeStart(cancel: () => void): Emitted immediately before starting; call cancel() to prevent the worker from starting.

  • stop(escalate: () => void): Emitted immediately when stop() is called; call escalate() to force an immediate stop regardless of the forceTerminate argument that was passed.

  • end: Emitted once the worker has fully stopped (after stop, once schedMsg and the supervisor have both finished shutting down, and – unless config.unmanaged is set – once the new worker-management bookkeeping for the run has been flushed).

  • error: Emitted when an internal error occurs (including errors thrown by start()/stop() and unhandled warning/error conditions from the supervisor).

  • warning: Emitted for a non-fatal problem worth surfacing to the user. The callback argument is a message string.

  • sandbox: Emitted when the worker instantiates a new sandbox. The argument provided to the callback is a SandboxHandle, not a Sandbox instance – see Sandbox API, below.

  • connect / disconnect: Emitted when the worker’s scheduler connection connects/disconnects.

  • beforeFetch(cancel: () => void): Emitted immediately before the worker requests slices from the scheduler; call cancel() to skip this fetch.

  • fetch: Emitted once a fetch request to the scheduler completes, whether or not it returned any work (this includes fetches that found no slices available). The callback argument is either an object { fetchStart, fetchEnd, fetchSize, jobs, fetchState } describing what was fetched, or, if the request itself failed, the Error instance.

  • beforeResult(cancel: () => void, resultUrl: string | false, jobAddress: string, sliceNumber: number): Emitted immediately before the worker submits a completed slice’s result to the scheduler; call cancel() to abort the submission (the slice is returned to the scheduler instead).

  • result: Emitted once a result submission completes. On success, the callback receives (resultUrl: string | false, payloadLength: number, jobAddress: string, sliceNumber: number); on failure (after retries are exhausted), it receives (error: Error, jobAddress: string, sliceNumber: number).

  • payment: Emitted immediately after a successful result, once payment has been recorded. The callback receives (amount: string, paymentAddress: string, jobAddress: string, sliceNumber: number) – there is no single payload object, and no accepted/reason fields (a slice that wasn’t accepted doesn’t reach this event; see result, above).

  • drop-slice: Emitted when a slice is returned/dropped outside the normal result-submission flow (e.g. the SIGHUP handler dropping all sandboxes). The callback receives { jobId, sliceNumber, status }.

  • metrics: Emitted alongside slice completion, carrying instrumentation data: { jobId, sliceNumber, metrics, status }.

  • notification: Emitted when the worker receives a job-level notification from the scheduler (the counterpart, at the worker/scheduler layer, of the Protocol API’s Notification message – see Protocol API). The callback receives (eventName, resolveCallback); call resolveCallback() once you’ve finished handling it.

  • claim: Emitted once, near the start of start(), after any previously-unclaimed earnings for this worker have been automatically transferred to config.paymentAddress (skipped when config.claimedEarnings === false or config.managed === false). The callback receives the transfer’s payload.

Note

fetch2 also exists, as a forward-looking variant of fetch (with jobs keyed differently); it is not yet part of the stable public contract.

Note

The claim/metrics/drop-slice/notification events reflect an automatic earnings-claim/registration/telemetry subsystem; treat the four event descriptions above as a starting point rather than an exhaustive contract.

Note

One known issue: a catch block in the supervisor’s sandbox-startup error handling (worker/supervisor2/index.js) does this.worker.emit(error) instead of this.worker.emit('error', error), so a worker.on('error', ...) listener won’t fire for that particular failure path.

Sandbox API

There are two distinct sandbox-related objects. worker.sandboxes/worker.workingSandboxes return Sandbox instances – the supervisor’s own internal objects. The sandbox event, however, hands listeners a lighter-weight SandboxHandle (exposing just id, public, jobAddress, and sliceNumber), and it’s the SandboxHandle that emits the per-slice lifecycle events most consumers actually want. Both are EventEmitters, but they emit different events, described separately below.

SandboxHandle Events

These are the events emitted on the SandboxHandle object provided by the worker’s sandbox event.

  • ready: Emitted when the sandbox is available and waiting to be assigned a slice (including when it becomes available again for reuse after finishing one).

  • job: Emitted once the sandbox is associated with a specific job, before it starts on that job’s first slice. The callback argument is the job’s JobHandle.

  • slice: Emitted when the sandbox begins working on a slice. The callback argument is the slice number (not a job description object).

  • sliceEnd: Emitted when the sandbox finishes working on a slice (success or failure). The callback argument is the slice number.

  • progress: Emitted when the slice reports progress. The callback argument is the progress value (a number between 0 and 100), or undefined for indeterminate/out-of-range progress reports.

  • payment: Emitted alongside the worker’s own payment event (see Events, above), for the slice this sandbox most recently worked on. The callback receives (amount: string, paymentAddress: string, sliceNumber: number).

  • metrics: Emitted alongside slice completion with per-sandbox instrumentation. The callback receives (sliceNumber: number, eventMeasurements: object).

  • end: Emitted when the sandbox environment is terminated. The sandbox will not be used after this event is emitted.

Sandbox Events

These are emitted directly on the Sandbox instances found in worker.sandboxes/worker.workingSandboxes (not on their SandboxHandle):

  • start: Emitted when the sandbox begins working on a slice. The callback receives { job, sandbox }, where job is the job’s public metadata (job.public from the Compute API) and sandbox is this Sandbox instance.

  • sandboxError: Emitted when the sandbox environment itself (as opposed to the work function running inside it) hits an error condition. The callback argument is the error.

  • reject: Emitted when the sandbox is terminated while a slice was in progress. The callback argument is an Error describing the termination.

Overriding SchedMsg Handlers

The worker’s SchedMsg instance (worker.schedMsg) subscribes to global commands from the scheduler. It contains default handlers for cross-platform handling of commands, but they can be overriden for clients to provide their own behaviour.

The scheduler’s commands are propagated in the SchedMsg instance by means of it being an EventEmitter. Additional event listeners can be registered, and listeners will be executed in LIFO (last-in-first-out) order. This means that if you add your own listener, it will be run before the default one.

If a command listener returns false then it will cancel the execution of the remaining listeners. This is the recommended method of overriding the default listener:

const worker = new DistributiveWorker(config);
worker.schedMsg.on("restart", () => {
  console.log("The scheduler asked this worker to restart.");
  return false; // cancel the default behaviour
});

Note

registerHandler (used internally to wire up each command’s default listener) throws if called twice for the same command, so only commands with a default handler – listed below – can be overridden this way. Attempting to register the first listener for a command with no default (e.g. one made up for a custom application) works fine; there’s just nothing to cancel.

SchedMsg Commands

Every payload property below is named jobId; the corresponding handlers read/write worker.config.jobIds (see Constructor, above).

  • kill: This command instructs the worker to immediately stop working, and can optionally disable the worker to prevent restarting. The user will need to manually intervene to restart the worker.
    Payload Object:

    • temporary: boolean: When false, the worker will be disabled.

  • restart: Currently broken. The handler is a one-line throw new Error('not supported'); a scheduler that sends this command today will cause the handler to throw synchronously out of SchedMsg.onMessage().

  • remove: This command instructs the worker to stop working on a specific job.
    Payload Object:

    • jobId: string: The id of the job to stop working on.

  • addPriorityJob: This command adds a job id to worker.config.jobIds, restricting (or further restricting) this worker to computing slices from the listed jobs.
    Payload Object:

    • jobId: string: The id of the job to add.

    • immediate: boolean: When true, also immediately returns any in-progress slices/sandboxes not working on a priority job.

  • removePriorityJob: The inverse of addPriorityJob: removes a job id from worker.config.jobIds.
    Payload Object:

    • jobId: string: The id of the job to remove.

    • immediate: boolean: When true, also immediately returns any in-progress slices/sandboxes working on this job.

Note

There is no default handler for announce, reload, or openPopup – a worker receiving one of these commands just logs No SchedMsg handler registered for command '<name>' and otherwise ignores it. An application can register its own listener for any of these command names to give them real behaviour.