Basic DCP Job Tutorial (Web Browser)ο
This tutorial demonstrates how to create and run a simple DCP Job in a web browser. You will learn how to:
Define an input set of data to be processed in parallel.
Write a worker function that operates on each element.
Configure a Job, including public metadata and compute groups.
Attach event listeners to monitor job progress, results, and errors.
Execute the Job and post-process the results.
The example converts a string of lowercase characters into uppercase letters using the Distributive Compute Platform (DCP), giving you a hands-on introduction to distributed computation.
π‘ The complete code is available in the Full Code section at the bottom of this page.
A more advanced tutorial will follow, covering topics such as:
Specifying slice payment offers and alternate payment accounts.
Working with remote datasets.
Deploying jobs across multiple compute groups in federated networks.
This tutorial focuses on the core building blocks so you can get a Job running quickly and safely.
Requirementsο
A modern web browser
A DCP Portal account
DCP Jobο
Create an HTML file called toUpperCase.html. The page needs a button to trigger the job and a text area to display output:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<!-- DCP scripts go here -->
</head>
<body>
<br>
<button id="deploy-btn" onclick="main()">Deploy Job</button>
<br><br>
<textarea id="jobConsole" cols="120" rows="30"></textarea>
</body>
</html>
Initialize DCP and define main()ο
Inside the <head> element, add this script tag to load the DCP client bundle:
<script src="https://scheduler.distributed.computer/dcp-client/dcp-client.js"></script>
This loads the DCP client and connects to the public DCP scheduler, exposing the dcp global object. Additional schedulers may be available in the future, allowing job deployers to select a specific target scheduler.
Then define your main function in a second script tag:
<script>
async function main() {
/* DCP App... */
};
</script>
Learn moreο
Logging Functionο
Since worker output isnβt visible in the browserβs DevTools the same way it is in Node.js, define a helper inside main() that appends messages to the text area:
const consoleEl = document.querySelector('#jobConsole');
const log = (msg) => {
consoleEl.value += msg + '\n';
consoleEl.scrollTop = consoleEl.scrollHeight;
};
consoleElreferences the<textarea>element in the page.Each call to
log()appends a new line and scrolls to the bottom automatically.
Input Setο
The input set is an array of enumerable values (e.g., integers, strings, objects, images). Each element in the array is treated as an independent input datum and processed in parallel by DCP workers.
In this example, the input set is an array of characters derived from the string "yelling!".
const inputSet = Array.from('yelling!');
Work Functionο
The work function defines the computation applied to each element of the input set. DCP serializes this function and distributes it to Workers, where it is executed independently for each input datum in parallel.
Each Worker receives a single input element and returns a corresponding result. Because execution is isolated per input, the work function should be deterministic and self-contained.
In this example, each Worker receives one character and converts it to uppercase:
async function workFunction(letter) {
progress();
return letter.toUpperCase();
}
letteris one element from the input set.progress()reports task progress back to the scheduler.The return value becomes one element in the final results array.
When the job completes, the results are returned in the same order as the original input set.
Learn more:ο
Jobο
A Job represents the workload to be executed across the DCP network. Each element of the input set is packaged as a Job slice and processed independently by Workers in parallel. Jobs encapsulate the input, the work function, and optional configuration such as compute groups, public metadata, and event handlers.
const job = compute.for(inputSet, workFunction);
At this point, the job object can be further configured before execution (see Job Configuration below).
Learn moreο
Job Configurationο
After creating a job with compute.for(...), you can configure its behavior and metadata by setting properties on the job object before calling job.exec().
Public informationο
You may attach optional, publicly visible metadata to your job. This information can be displayed in dashboards or monitoring tools and helps identify the purpose of the job.
job.public = {
name: 'toUpperCase',
description: 'Minimal demonstration of a distributed job',
link: 'https://distributive.network'
};
nameβ A short identifier for the jobdescriptionβ A brief explanation of what the job doeslinkβ Optional reference URL for additional context
This metadata does not affect execution behavior; it is informational only.
Compute Groupsο
DCP jobs can be deployed to one or more compute groups. A compute group may be public (such as the Global DCP group) or private. To deploy into a private group, you must have the appropriate join credentials.
Security note: Never hard-code joinSecret values in production code. Prompt for them at runtime or load them securely from environment variables. Any hard-coded secrets shown in examples are for demonstration purposes only.
If no compute group is specified, the job is deployed to the public Global DCP group by default.
Deploy to a Private Compute Groupο
job.computeGroups = [
{ joinKey: '<key>', joinSecret: '<secret>' }
];
Deploy to Multiple Private Compute Groupsο
job.computeGroups = [
{ joinKey: '<key1>', joinSecret: '<secret1>' },
{ joinKey: '<key2>', joinSecret: '<secret2>' },
{ joinKey: '<key3>', joinSecret: '<secret3>' },
];
Deploy to Both Public and Private Groupsο
To deploy to a private group and the public Global DCP group:
job.computeGroups = [
{ joinKey: '<key>', joinSecret: '<secret>' },
{ joinKey: 'public' }
];
Each listed group becomes eligible to execute slices of the job.
Event Listenersο
DCP Jobs support a variety of optional event listeners that let you monitor execution, track results, and handle errors in real time. You can attach listeners to the job object before calling job.exec(). configure some optional events.
Ready State Changeο
Fires whenever the jobβs ready state changes. States typically include: exec, init, preauth, deploying, listeners, compute-groups, uploading, and deployed.
job.on('readystatechange', (ev) => log(`Ready state: ${ev}`));
Acceptedο
Fires when the job is accepted by the DCP Scheduler. At this point, the job is assigned a unique ID that can be displayed or logged.
job.on('accepted', () => log(` Job id: ${job.id}\n Awaiting results...`));
Resultο
Fires whenever a Worker returns a result. These events may arrive out of order relative to the input set. The final output from job.exec() is collated in the original input order.
job.on('result', (ev) => log(`${JSON.stringify(ev)}`));
Errorο
Fires whenever a Worker encounters an error while processing a job slice. You can use this to debug or handle failures gracefully.
job.on('error', (err) => log(` Job error: ${JSON.stringify(err, null, 2)}`));
Consoleο
Allows capturing console.log calls from Workers. Since Worker code runs remotely, its console output isnβt visible locally unless you listen for this event. Useful for debugging distributed computations.
job.on('console', (ev) => log(`${JSON.stringify(console, null, 2)}`));
No Fundsο
Fires when the account paying for the job does not have sufficient funds to continue processing. The job is paused until the account is topped up.
job.on('nofunds', (ev) => log(`${JSON.stringify(ev, null, 2)}`));
Stopο
Fires when the job is stopped manually or via the scheduler. In most cases, this is optional, since job.exec() resolves when all results are returned.
job.on('stop', (ev) => log(`${JSON.stringify(ev, null, 2)}`));
Job Executionο
Execute the job by calling job.exec(). This submits the job to the scheduler and returns a Promise that resolves when all slices have completed.
let results = await job.exec();
The resolved value contains the jobβs results.
By default:
The Job is associated with the identity of the DCP Portal account, and is payed for by the selected DCP Bank account.
If no additional arguments are provided, the job will be paid for at the current
marketRate.
Advanced topics such as using alternate payment accounts, customizing slice payment offers, and remote datasets will be covered in the next tutorial.
Learn moreο
Result Post-Processingο
Once execution completes, you can process the returned results as needed. In this example, we convert the results into an array, concatenate the characters, and print the final string.
let RESULTS = Array.from(results).join('');
log(RESULTS);
This produces the fully reconstructed uppercase string.
Run itο
Ensure you have a DCP Portal account with Compute Credits.
1. With a web browser, open:
toUpperCase.html
2. Click the Deploy Job buttuon and observe the job submission and execution:
Job events (accepted, results, errors) will be logged in real time.
Once complete, the final uppercase string will be printed to the console.
3. Example text area output:
Ready state: exec
Ready state: init
Ready state: preauth
Ready state: deploying
Ready state: listeners
Ready state: compute-groups
Ready state: uploading
Ready state: deployed
Job id: jxCJXnm9pKJu2oOXFGe8bg
Awaiting results...
{"job":"jxCJXnm9pKJu2oOXFGe8bg","sliceNumber":1,"result":"Y"}
{"job":"jxCJXnm9pKJu2oOXFGe8bg","sliceNumber":2,"result":"E"}
{"job":"jxCJXnm9pKJu2oOXFGe8bg","sliceNumber":3,"result":"L"}
{"job":"jxCJXnm9pKJu2oOXFGe8bg","sliceNumber":4,"result":"L"}
{"job":"jxCJXnm9pKJu2oOXFGe8bg","sliceNumber":6,"result":"N"}
{"job":"jxCJXnm9pKJu2oOXFGe8bg","sliceNumber":5,"result":"I"}
{"job":"jxCJXnm9pKJu2oOXFGe8bg","sliceNumber":7,"result":"G"}
{"job":"jxCJXnm9pKJu2oOXFGe8bg","sliceNumber":8,"result":"!"}
YELLING!
This demonstrates how DCP distributes computation across workers, even for simple tasks like converting characters to uppercase.
Full Codeο
The following example combines all the concepts covered in this tutorial: input set definition, work function, job configuration, compute groups, event handling, execution, and result post-processing. Running this code will convert the string βyelling!β to uppercase using DCP Workers.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<script src="https://scheduler.distributed.computer/dcp-client/dcp-client.js"></script>
<script>
async function main() {
const compute = dcp.compute;
/* LOGGING */
const consoleEl = document.querySelector('#jobConsole');
const log = (msg) => {
consoleEl.value += msg + '\n';
consoleEl.scrollTop = consoleEl.scrollHeight;
};
/* INPUT SET */
const inputSet = Array.from('yelling!');
/* WORK FUNCTION */
async function workFunction(letter) {
progress();
return letter.toUpperCase();
};
/* COMPUTE FOR */
const job = compute.for(inputSet, workFunction);
/* COMPUTE GROUPS */
job.computeGroups = [
{ joinKey: 'demo', joinSecret: 'dcp' },
{ joinKey: 'public' }
];
/* PUBLIC INFO */
job.public = {
name: 'toUpperCase',
description: 'Minimal demonstration of a distributed job',
link: 'https://distributive.network'
};
/* EVENTS */
job.on('readystatechange', (ev) => log(`Ready state: ${ev}`));
job.on('accepted', () => log(` Job id: ${job.id}\n Awaiting results...`));
job.on('result', (ev) => log(`${JSON.stringify(ev)}`));
job.on('error', (err) => log(` Job error: ${JSON.stringify(err, null, 2)}`));
job.on('nofunds', (ev) => log(`${JSON.stringify(ev, null, 2)}`));
job.on('console', (con) => log(`${JSON.stringify(con, null, 2)}`));
/* EXECUTION */
let results = await job.exec();
/* RESULTS */
let RESULTS = Array.from(results).join('');
log(RESULTS);
}
</script>
</head>
<body>
<br>
<button id="deploy-btn" onclick="main()">Deploy Job</button>
<br><br>
<textarea id="jobConsole" cols="120" rows="30"></textarea>
</body>
</html>
When executed, the browser will prompt for a DCP account, the job will then be submitted to the DCP scheduler, distributed across workers, and the final uppercase string is printed to the text area. You can observe job events such as acceptance, results, and errors in real time.
This complete example provides a foundation you can modify to experiment with different input sets, work functions, and compute group configurations.