Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a0408c1

Browse files
committedJan 16, 2025·
Added Quickstart for Javascript Jobs HTTP api
Signed-off-by: Constantin Chirila <constantin.chirila@gmail.com>
1 parent c32f421 commit a0408c1

File tree

9 files changed

+1872
-0
lines changed

9 files changed

+1872
-0
lines changed
 

‎jobs/javascript/http/README.md

+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# Dapr Jobs
2+
3+
In this quickstart, you'll schedule, get, and delete a job using Dapr's Job API. This API is responsible for scheduling and running jobs at a specific time or interval.
4+
5+
Visit [this](https://v1-14.docs.dapr.io/developing-applications/building-blocks/jobs/) link for more information about Dapr and the Jobs API.
6+
7+
> **Note:** This example leverages HTTP `requests` only. If you are looking for the example using the Dapr Client SDK (recommended) [click here](../sdk/).
8+
9+
This quickstart includes two apps:
10+
11+
- `job-scheduler`, responsible for scheduling, retrieving and deleting jobs.
12+
- `job-service`, responsible for handling the triggered jobs.
13+
14+
## Run the app with the template file
15+
16+
This section shows how to run both applications at once using [multi-app run template files](https://docs.dapr.io/developing-applications/local-development/multi-app-dapr-run/multi-app-overview/) with `dapr run -f .`. This enables to you test the interactions between multiple applications and will `schedule`, `run`, `get`, and `delete` jobs within a single process.
17+
18+
1. Install dependencies:
19+
20+
<!-- STEP
21+
name: Install Node dependencies
22+
-->
23+
24+
```bash
25+
cd ./job-service
26+
npm install
27+
cd ..
28+
cd ./job-scheduler
29+
npm install
30+
```
31+
32+
<!-- END_STEP -->
33+
34+
2. Open a new terminal window and run the multi app run template:
35+
36+
<!-- STEP
37+
name: Run multi app run template
38+
expected_stdout_lines:
39+
- '== APP - job-scheduler == Job Scheduled: R2-D2'
40+
- '== APP - job-scheduler == Job Scheduled: C-3PO'
41+
- '== APP - job-service == Received job request...'
42+
- '== APP - job-service == Starting droid: R2-D2'
43+
- '== APP - job-service == Executing maintenance job: Oil Change'
44+
- '== APP - job-service == Received job request...'
45+
- '== APP - job-service == Starting droid: C-3PO'
46+
- '== APP - job-service == Executing maintenance job: Limb Calibration'
47+
expected_stderr_lines:
48+
output_match_mode: substring
49+
match_order: none
50+
background: false
51+
sleep: 60
52+
timeout_seconds: 120
53+
-->
54+
55+
```bash
56+
dapr run -f .
57+
```
58+
59+
The terminal console output should look similar to this, where:
60+
61+
- The `R2-D2` job is being scheduled.
62+
- The `R2-D2` job is being retrieved.
63+
- The `C-3PO` job is being scheduled.
64+
- The `C-3PO` job is being retrieved.
65+
- The `R2-D2` job is being executed after 15 seconds.
66+
- The `C-3PO` job is being executed after 20 seconds.
67+
68+
```text
69+
== APP - job-scheduler == Job Scheduled: R2-D2
70+
== APP - job-scheduler == Job details: {"name":"R2-D2", "dueTime":"15s", "data":{"value":{"value":"R2-D2:Oil Change"}}}
71+
== APP - job-scheduler == Job Scheduled: C-3PO
72+
== APP - job-scheduler == Job details: {"name":"C-3PO", "dueTime":"20s", "data":{"value":{"value":"C-3PO:Limb Calibration"}}}
73+
== APP - job-service == Received job request...
74+
== APP - job-service == Starting droid: R2-D2
75+
== APP - job-service == Executing maintenance job: Oil Change
76+
```
77+
78+
After 20 seconds, the terminal output should present the `C-3PO` job being processed:
79+
80+
```text
81+
== APP - job-service == Received job request...
82+
== APP - job-service == Starting droid: C-3PO
83+
== APP - job-service == Executing maintenance job: Limb Calibration
84+
```
85+
86+
<!-- END_STEP -->
87+
88+
## Run the Jobs APIs individually
89+
90+
### Schedule Jobs
91+
92+
1. Open a terminal and run the `job-service` app:
93+
94+
```bash
95+
dapr run --app-id job-service --app-port 6200 --dapr-http-port 6280 -- go run .
96+
```
97+
98+
2. On a new terminal window, schedule the `R2-D2` Job using the Jobs API.
99+
100+
```bash
101+
curl -X POST \
102+
http://localhost:6280/v1.0-alpha1/jobs/R2D2 \
103+
-H "Content-Type: application/json" \
104+
-d '{
105+
"data": {
106+
"value": "R2-D2:Oil Change"
107+
},
108+
"dueTime": "2s"
109+
}'
110+
```
111+
112+
Back at the `job-service` app terminal window, the output should be:
113+
114+
```text
115+
== APP - job-app == Received job request...
116+
== APP - job-app == Starting droid: R2-D2
117+
== APP - job-app == Executing maintenance job: Oil Change
118+
```
119+
120+
3. On the same terminal window, schedule the `C-3PO` Job using the Jobs API.
121+
122+
```bash
123+
curl -X POST \
124+
http://localhost:6280/v1.0-alpha1/jobs/c-3po \
125+
-H "Content-Type: application/json" \
126+
-d '{
127+
"data": {
128+
"value": "C-3PO:Limb Calibration"
129+
},
130+
"dueTime": "30s"
131+
}'
132+
```
133+
134+
### Get a scheduled job
135+
136+
1. On the same terminal window, run the command below to get the recently scheduled `C-3PO` job.
137+
138+
```bash
139+
curl -X GET http://localhost:6280/v1.0-alpha1/jobs/c-3po -H "Content-Type: application/json"
140+
```
141+
142+
You should see the following:
143+
144+
```text
145+
{"name":"C-3PO", "dueTime":"30s", "data":{"@type":"type.googleapis.com/google.protobuf.StringValue", "expression":"C-3PO:Limb Calibration"}}
146+
```
147+
148+
### Delete a scheduled job
149+
150+
1. On the same terminal window, run the command below to deleted the recently scheduled `C-3PO` job.
151+
152+
```bash
153+
curl -X DELETE http://localhost:6280/v1.0-alpha1/jobs/c-3po -H "Content-Type: application/json"
154+
```
155+
156+
2. Run the command below to attempt to retrieve the deleted job:
157+
158+
```bash
159+
curl -X GET http://localhost:6280/v1.0-alpha1/jobs/c-3po -H "Content-Type: application/json"
160+
```
161+
162+
Back at the `job-service` app terminal window, the output should be:
163+
164+
```text
165+
ERRO[0249] Error getting job c-3po due to: rpc error: code = Unknown desc = job not found: app||default||job-service||c-3po instance=diagrid.local scope=dapr.api type=log ver=1.14.0-rc.2
166+
```

‎jobs/javascript/http/dapr.yaml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
version: 1
2+
apps:
3+
- appDirPath: ./job-service/
4+
appID: job-service
5+
appPort: 6200
6+
daprHTTPPort: 6280
7+
schedulerHostAddress: localhost
8+
command: ["npm", "run", "start"]
9+
- appDirPath: ./job-scheduler/
10+
appID: job-scheduler
11+
appPort: 6300
12+
daprHTTPPort: 6380
13+
command: ["npm", "run", "start"]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Job request bodies
2+
const c3poJobBody = {
3+
data: {
4+
value: "C-3PO:Limb Calibration",
5+
},
6+
dueTime: "20s",
7+
};
8+
9+
const r2d2JobBody = {
10+
data: {
11+
value: "R2-D2:Oil Change",
12+
},
13+
dueTime: "15s",
14+
};
15+
const daprHost = process.env.DAPR_HOST || "http://localhost";
16+
const schedulerDaprHttpPort = "6280";
17+
18+
async function main() {
19+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
20+
// Wait for job-service to start
21+
await sleep(5000);
22+
23+
try {
24+
// Schedule R2-D2 job
25+
await scheduleJob("R2-D2", r2d2JobBody);
26+
await sleep(5000);
27+
// Get R2-D2 job details
28+
await getJobDetails("R2-D2");
29+
30+
// Schedule C-3PO job
31+
await scheduleJob("C-3PO", c3poJobBody);
32+
await sleep(5000);
33+
// Get C-3PO job details
34+
await getJobDetails("C-3PO");
35+
36+
await sleep(30000);
37+
} catch (error) {
38+
if (error.name === "AbortError") {
39+
console.error("Request timed out");
40+
} else {
41+
console.error("Error:", error.message);
42+
}
43+
process.exit(1);
44+
}
45+
}
46+
47+
async function scheduleJob(jobName, jobBody) {
48+
const reqURL = `${daprHost}:${schedulerDaprHttpPort}/v1.0-alpha1/jobs/${jobName}`;
49+
const response = await fetch(reqURL, {
50+
method: "POST",
51+
headers: {
52+
"Content-Type": "application/json",
53+
},
54+
body: JSON.stringify(jobBody),
55+
});
56+
57+
if (response.status !== 204) {
58+
throw new Error(
59+
`Failed to register job event handler. Status code: ${response.status}`
60+
);
61+
}
62+
63+
console.log("Job Scheduled:", jobName);
64+
}
65+
66+
async function getJobDetails(jobName) {
67+
const reqURL = `${daprHost}:${schedulerDaprHttpPort}/v1.0-alpha1/jobs/${jobName}`;
68+
const response = await fetch(reqURL, {
69+
method: "GET",
70+
});
71+
if (!response.ok) {
72+
throw new Error(`HTTP error! status: ${response.status}`);
73+
}
74+
const jobDetails = await response.text();
75+
console.log("Job details:", jobDetails);
76+
}
77+
78+
main().catch(console.error);

‎jobs/javascript/http/job-scheduler/package-lock.json

+765
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "order-processor",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"type": "module",
7+
"scripts": {
8+
"start": "node index.js",
9+
"start:dapr": "dapr run --app-port 5001 --app-id order-processing --app-protocol http --dapr-http-port 3501 --resources-path ../../../components -- npm run start"
10+
},
11+
"keywords": [],
12+
"author": "",
13+
"license": "ISC",
14+
"dependencies": {
15+
"express": "^4.17.2",
16+
"body-parser": "^1.19.0"
17+
}
18+
}
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import express from "express";
2+
3+
const app = express();
4+
5+
// Middleware to parse JSON bodies
6+
app.use(express.json());
7+
8+
// Start server
9+
const appPort = process.env.APP_PORT || "6200";
10+
app
11+
.listen(appPort, () => {
12+
console.log(`Server started on port ${appPort}`);
13+
})
14+
.on("error", (err) => {
15+
console.error("Failed to start server:", err);
16+
process.exit(1);
17+
});
18+
19+
function setDroidJob(droidStr) {
20+
const [droid, task] = droidStr.split(":");
21+
22+
return {
23+
droid,
24+
task,
25+
};
26+
}
27+
28+
// Job handler route
29+
app.post("/job/*", (req, res) => {
30+
console.log("Received job request...");
31+
32+
try {
33+
const jobData = req.body;
34+
35+
// Creating Droid Job from decoded value
36+
const droidJob = setDroidJob(jobData.value);
37+
38+
console.log("Starting droid:", droidJob.droid);
39+
console.log("Executing maintenance job:", droidJob.task);
40+
res.status(200).end();
41+
} catch (error) {
42+
console.error("Error processing job:", error);
43+
res.status(400).json({
44+
error: `Error processing request: ${error.message}`,
45+
});
46+
}
47+
});

‎jobs/javascript/http/job-service/package-lock.json

+765
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "order-processor",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"type": "module",
7+
"scripts": {
8+
"start": "node index.js",
9+
"start:dapr": "dapr run --app-port 5001 --app-id order-processing --app-protocol http --dapr-http-port 3501 --resources-path ../../../components -- npm run start"
10+
},
11+
"keywords": [],
12+
"author": "",
13+
"license": "ISC",
14+
"dependencies": {
15+
"express": "^4.17.2",
16+
"body-parser": "^1.19.0"
17+
}
18+
}

‎jobs/javascript/http/makefile

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
include ../../../docker.mk
2+
include ../../../validate.mk

0 commit comments

Comments
 (0)
Please sign in to comment.