Skip to content

Commit e87a963

Browse files
authored
Merge pull request #1166 from alicejgibbons/release-1.15
Dotnet Jobs SDK qs
2 parents 7b4c935 + 04e9c2a commit e87a963

File tree

10 files changed

+554
-0
lines changed

10 files changed

+554
-0
lines changed

jobs/csharp/sdk/README.md

+185
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
# Dapr Jobs API (SDK)
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://docs.dapr.io/developing-applications/building-blocks/jobs/) link for more information about Dapr and the Jobs API.
6+
7+
> **Note:** This example leverages the Dotnet SDK. If you are looking for the example using only HTTP requests, [click here](../http/).
8+
9+
This quickstart includes two apps:
10+
11+
- Jobs Scheduler, responsible for scheduling, retrieving and deleting jobs.
12+
- Jobs Service, responsible for handling the triggered jobs.
13+
14+
## Run all apps with multi-app run 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. Build the apps:
19+
20+
<!-- STEP
21+
name: Build dependencies for job-service
22+
sleep: 1
23+
-->
24+
25+
```bash
26+
cd ./job-service
27+
dotnet build
28+
```
29+
30+
<!-- END_STEP -->
31+
32+
<!-- STEP
33+
name: Build dependencies for job-scheduler
34+
sleep: 1
35+
-->
36+
37+
```bash
38+
cd ./job-scheduler
39+
dotnet build
40+
```
41+
42+
<!-- END_STEP -->
43+
44+
2. Run the multi app run template:
45+
46+
<!-- STEP
47+
name: Run multi app run template
48+
expected_stdout_lines:
49+
- '== APP - job-service-sdk == Job Scheduled: R2-D2'
50+
- '== APP - job-service-sdk == Job Scheduled: C-3PO'
51+
- '== APP - job-service-sdk == Starting droid: R2-D2'
52+
- '== APP - job-service-sdk == Executing maintenance job: Oil Change'
53+
- '== APP - job-service-sdk == Starting droid: C-3PO'
54+
- '== APP - job-service-sdk == Executing maintenance job: Limb Calibration'
55+
expected_stderr_lines:
56+
output_match_mode: substring
57+
match_order: none
58+
background: true
59+
sleep: 60
60+
timeout_seconds: 120
61+
-->
62+
63+
```bash
64+
dapr run -f .
65+
```
66+
67+
The terminal console output should look similar to this, where:
68+
69+
- The `R2-D2` job is being scheduled.
70+
- The `R2-D2` job is being retrieved.
71+
- The `C-3PO` job is being scheduled.
72+
- The `C-3PO` job is being retrieved.
73+
- The `R2-D2` job is being executed after 15 seconds.
74+
- The `C-3PO` job is being executed after 20 seconds.
75+
76+
```text
77+
== APP - job-scheduler-sdk == Scheduling job...
78+
== APP - job-service-sdk == Job Scheduled: R2-D2
79+
== APP - job-scheduler-sdk == Job scheduled: {"name":"R2-D2","job":"Oil Change","dueTime":15}
80+
== APP - job-scheduler-sdk == Getting job: R2-D2
81+
== APP - job-service-sdk == Getting job...
82+
== APP - job-scheduler-sdk == Job details: {"schedule":"@every 15s","repeatCount":1,"dueTime":null,"ttl":null,"payload":"ChtkYXByLmlvL3NjaGVkdWxlL2pvYnBheWxvYWQSJXsiZHJvaWQiOiJSMi1EMiIsInRhc2siOiJPaWwgQ2hhbmdlIn0="}
83+
== APP - job-scheduler-sdk == Scheduling job...
84+
== APP - job-service-sdk == Job Scheduled: C-3PO
85+
== APP - job-scheduler-sdk == Job scheduled: {"name":"C-3PO","job":"Limb Calibration","dueTime":20}
86+
== APP - job-scheduler-sdk == Getting job: C-3PO
87+
== APP - job-service-sdk == Getting job...
88+
== APP - job-scheduler-sdk == Job details: {"schedule":"@every 20s","repeatCount":1,"dueTime":null,"ttl":null,"payload":"ChtkYXByLmlvL3NjaGVkdWxlL2pvYnBheWxvYWQSK3siZHJvaWQiOiJDLTNQTyIsInRhc2siOiJMaW1iIENhbGlicmF0aW9uIn0="}
89+
== APP - job-service-sdk == Handling job...
90+
== APP - job-service-sdk == Starting droid: R2-D2
91+
== APP - job-service-sdk == Executing maintenance job: Oil Change
92+
```
93+
94+
After 20 seconds, the terminal output should present the `C-3PO` job being processed:
95+
96+
```text
97+
== APP - job-service-sdk == Handling job...
98+
== APP - job-service-sdk == Starting droid: C-3PO
99+
== APP - job-service-sdk == Executing maintenance job: Limb Calibration
100+
```
101+
102+
<!-- END_STEP -->
103+
104+
## Run apps individually
105+
106+
### Schedule Jobs
107+
108+
1. Open a terminal and run the `job-service` app. Build the dependencies if you haven't already.
109+
110+
```bash
111+
cd ./job-service
112+
dotnet build
113+
```
114+
115+
```bash
116+
dapr run --app-id job-service-sdk --app-port 6200 --dapr-http-port 6280 -- dotnet run
117+
```
118+
119+
2. In a new terminal window, schedule the `R2-D2` Job using the Jobs API.
120+
121+
```bash
122+
curl -X POST \
123+
http://localhost:6200/scheduleJob \
124+
-H "Content-Type: application/json" \
125+
-d '{
126+
"name": "R2-D2",
127+
"job": "Oil Change",
128+
"dueTime": 2
129+
}'
130+
```
131+
132+
In the `job-service` terminal window, the output should be:
133+
134+
```text
135+
== APP - job-app == Received job request...
136+
== APP - job-app == Starting droid: R2-D2
137+
== APP - job-app == Executing maintenance job: Oil Change
138+
```
139+
140+
3. On the same terminal window, schedule the `C-3PO` Job using the Jobs API.
141+
142+
```bash
143+
curl -X POST \
144+
http://localhost:6200/scheduleJob \
145+
-H "Content-Type: application/json" \
146+
-d '{
147+
"name": "C-3PO",
148+
"job": "Limb Calibration",
149+
"dueTime": 30
150+
}'
151+
```
152+
153+
### Get a scheduled job
154+
155+
1. On the same terminal window, run the command below to get the recently scheduled `C-3PO` job.
156+
157+
```bash
158+
curl -X GET http://localhost:6200/getJob/C-3PO -H "Content-Type: application/json"
159+
```
160+
161+
You should see the following:
162+
163+
```text
164+
{"name":"c-3po", "dueTime":"30s", "data":{"@type":"type.googleapis.com/google.protobuf.Value", "value":{"Value":"C-3PO:Limb Calibration"}}}
165+
```
166+
167+
### Delete a scheduled job
168+
169+
1. On the same terminal window, run the command below to deleted the recently scheduled `C-3PO` job.
170+
171+
```bash
172+
curl -X DELETE http://localhost:6200/deleteJob/C-3PO -H "Content-Type: application/json"
173+
```
174+
175+
2. Run the command below to attempt to retrieve the deleted job:
176+
177+
```bash
178+
curl -X GET http://localhost:6200/getJob/C-3PO -H "Content-Type: application/json"
179+
```
180+
181+
In the `job-service` terminal window, the output should be similar to the following:
182+
183+
```text
184+
ERRO[0157] Error getting job C-3PO due to: rpc error: code = NotFound desc = job not found: C-3PO instance=local scope=dapr.api type=log ver=1.15.0
185+
```

jobs/csharp/sdk/dapr.yaml

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
version: 1
2+
apps:
3+
- appDirPath: ./job-service/
4+
appID: job-service-sdk
5+
appPort: 6200
6+
daprHTTPPort: 6280
7+
command: ["dotnet", "run"]
8+
appLogDestination: console
9+
daprdLogDestination: console
10+
- appDirPath: ./job-scheduler/
11+
appID: job-scheduler-sdk
12+
appPort: 6300
13+
daprHTTPPort: 6380
14+
command: ["dotnet", "run"]
15+
appLogDestination: console
16+
daprdLogDestination: console
+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#pragma warning disable CS0618 // Type or member is obsolete
2+
3+
using System.Text.Json.Serialization;
4+
using Dapr.Client;
5+
6+
var builder = WebApplication.CreateBuilder(args);
7+
var app = builder.Build();
8+
9+
await Task.Delay(5000); // Allow time for the job-service-sdk to start
10+
11+
// Instantiate an HTTP client for invoking the job-service-sdk application
12+
var httpClient = DaprClient.CreateInvokeHttpClient(appId: "job-service-sdk");
13+
14+
// Job details
15+
var r2d2Job = new DroidJob
16+
{
17+
Name = "R2-D2",
18+
Job = "Oil Change",
19+
DueTime = 15
20+
};
21+
22+
var c3poJob = new DroidJob
23+
{
24+
Name = "C-3PO",
25+
Job = "Limb Calibration",
26+
DueTime = 20
27+
};
28+
29+
await Task.Delay(50);
30+
31+
try
32+
{
33+
// Schedule R2-D2 job
34+
await ScheduleJob(r2d2Job);
35+
await Task.Delay(5000);
36+
// Get R2-D2 job details
37+
await GetJobDetails(r2d2Job);
38+
39+
// Schedule C-3PO job
40+
await ScheduleJob(c3poJob);
41+
await Task.Delay(5000);
42+
// Get C-3PO job details
43+
await GetJobDetails(c3poJob);
44+
45+
await Task.Delay(30000); // Allow time for jobs to complete
46+
}
47+
catch (Exception ex)
48+
{
49+
Console.Error.WriteLine($"Error: {ex.Message}");
50+
Environment.Exit(1);
51+
}
52+
53+
async Task ScheduleJob(DroidJob job)
54+
{
55+
Console.WriteLine($"Scheduling job...");
56+
57+
try
58+
{
59+
var response = await httpClient.PostAsJsonAsync("/scheduleJob", job);
60+
var result = await response.Content.ReadAsStringAsync();
61+
62+
response.EnsureSuccessStatusCode();
63+
Console.WriteLine($"Job scheduled: {result}");
64+
}
65+
catch (Exception e)
66+
{
67+
Console.WriteLine($"Error scheduling job: " + e);
68+
}
69+
}
70+
71+
async Task GetJobDetails(DroidJob job)
72+
{
73+
Console.WriteLine($"Getting job: " + job.Name);
74+
75+
try
76+
{
77+
var response = await httpClient.GetAsync($"/getJob/{job.Name}");
78+
var jobDetails = await response.Content.ReadAsStringAsync();
79+
80+
response.EnsureSuccessStatusCode();
81+
Console.WriteLine($"Job details: {jobDetails}");
82+
}
83+
catch (Exception e)
84+
{
85+
Console.WriteLine($"Error getting job: " + e);
86+
}
87+
}
88+
89+
await app.RunAsync();
90+
91+
public class DroidJob
92+
{
93+
[JsonPropertyName("name")]
94+
public string? Name { get; set; }
95+
96+
[JsonPropertyName("job")]
97+
public string? Job { get; set; }
98+
99+
[JsonPropertyName("dueTime")]
100+
public int DueTime { get; set; }
101+
}
102+
103+
#pragma warning restore CS0618 // Type or member is obsolete
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<RootNamespace>jobs_scheduler</RootNamespace>
7+
<ImplicitUsings>enable</ImplicitUsings>
8+
<Nullable>enable</Nullable>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="Dapr.Client" Version="1.15.0-rc07" />
13+
<PackageReference Include="Dapr.Jobs" Version="1.15.0-rc07" />
14+
</ItemGroup>
15+
16+
</Project>

0 commit comments

Comments
 (0)