Jobs Walkthrough¶
Jobs represent long-running or queued operations: model runs, batch exports, scheduled tasks. This page covers setup from package installation to first Swagger call.
The Job Entity¶
Job<TJobId, TTaskId> is the core entity. The default type parameters are Job<Guid, string>.
Key properties:
| Property | Type | Description |
|---|---|---|
Id |
Guid |
Unique job identifier (auto-generated) |
TaskId |
string |
Which task definition to run (maps to a workflow or executor) |
AccountId |
string |
The user/account that submitted the job |
Status |
JobStatus |
Current lifecycle status (see below) |
Progress |
int |
Completion percentage (0–100) |
Priority |
int |
Scheduling priority — higher values run first |
HostGroup |
string |
Tag that routes the job to a specific executor group |
Tag |
string |
Arbitrary label for filtering/grouping |
Parameters |
Dictionary<string,string> |
Key/value input parameters passed to the task |
Requested / Started / Finished |
DateTime? |
Lifecycle timestamps |
JobStatus Lifecycle¶
Pending → Starting → InProgress → Completed
↘ Error
↘ Cancelled (Cancel → Cancelling → Cancelled)
↘ TimedOut (TimingOut → TimedOut)
↘ CompletedUnsuccessfully
Full enum values:
| Value | Meaning |
|---|---|
Pending |
Submitted, waiting to be picked up by an executor |
Starting |
Executor has claimed the job and is starting it |
InProgress |
Actively running |
Completed |
Finished successfully |
Error |
Finished with an unhandled error |
Unknown |
Status cannot be determined |
Cancel |
Cancellation requested by the user |
Cancelling |
Executor is in the process of stopping the job |
Cancelled |
Job was successfully cancelled |
TimingOut |
Execution has exceeded the time limit |
TimedOut |
Job was stopped due to timeout |
CompletedUnsuccessfully |
Ran to completion but reported a failure result |
Removed |
Job record has been marked for removal |
Step 1 — Install the Package¶
dotnet add package DHI.Services.Jobs.WebApi
Step 2 — Register the Converters¶
In Program.cs, inside .AddJsonOptions(...):
options.JsonSerializerOptions.AddConverters(
DHI.Services.Jobs.WebApi.SerializerOptionsDefault.Options.Converters
);
Step 3 — Register the Service¶
Option A — Declarative (connections.json)¶
Add an entry in App_Data/connections.json:
{
"$type": "System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[DHI.Services.IConnection, DHI.Services]], mscorlib",
"wf-jobs": {
"$type": "DHI.Services.Jobs.WebApi.JobServiceConnection, DHI.Services.Jobs.WebApi",
"ConnectionString": "[AppData]jobs.json",
"RepositoryType": "DHI.Services.Jobs.JobRepository, DHI.Services.Jobs",
"Name": "Jobs (JSON)",
"Id": "wf-jobs"
}
}
Enable the connections repository in Program.cs:
Services.Configure(
new ConnectionRepository("[AppData]connections.json".Resolve()),
lazyCreation: true
);
Option B — Imperative (code)¶
Register directly in Program.cs:
ServiceLocator.Register(
new JobService<Workflow, string>(
new JobRepository("[AppData]jobs.json".Resolve()),
new TaskService<Workflow, string>(
new WorkflowRepository(
"[AppData]workflows.json".Resolve(),
SerializerOptionsDefault.Options.Converters
)
),
null
),
"wf-jobs"
);
The third argument to JobService is an optional IDiscreteService<Account, string> for account validation. Pass null to skip account validation during development.
Step 4 — SignalR Prerequisites¶
Jobs endpoints use SignalR for real-time status notifications. Register the dependencies in Program.cs:
builder.Services.AddSignalR();
builder.Services.AddSingleton<IFilterRepository>(
new FilterRepository("[AppData]signalr-filters.json".Resolve())
);
builder.Services.AddScoped<Microsoft.Extensions.Logging.ILogger>(_ =>
new SimpleLogger("[AppData]jobs.log".Resolve())
);
Note:
signalr-filters.jsonandjobs.logdo not need to exist — these registrations satisfy DI. The files are created automatically when data is first written.
Step 5 — Add Sample Data Files¶
Create App_Data/jobs.json with an empty dictionary to start:
{
"$type": "System.Collections.Generic.Dictionary`2[[System.Guid, System.Private.CoreLib],[DHI.Services.Jobs.Job`2[[System.Guid, System.Private.CoreLib],[System.String, System.Private.CoreLib]], DHI.Services.Jobs]], System.Private.CoreLib"
}
Step 6 — Test in Swagger¶
Start the API and open Swagger. You should see /api/jobs/... endpoints.
Submit a new job:
POST /api/jobs/wf-jobs
Request body:
{
"TaskId": "WriteToFile",
"Priority": 1,
"HostGroup": "Minion",
"Tag": "demo"
}
Get all jobs:
GET /api/jobs/wf-jobs
Get a specific job by ID:
GET /api/jobs/wf-jobs/{jobId}
The new job starts with Status: "Pending". An executor (Job Runner or Orchestrator) must pick it up to advance the status.
Next Steps: Executors and Automation¶
This walkthrough sets up the Jobs API (storage and status management). To actually run jobs you need an executor:
| Component | NuGet package | Role |
|---|---|---|
| Job Runner | DHI.Services.Jobs.Executer |
Polls for pending jobs and executes them in-process |
| Orchestrator | DHI.Services.Jobs.Orchestrator |
Manages multiple executors and load balancing |
| Workflow Worker | DHI.Services.Jobs.WorkflowWorker |
Executes Windows Workflow Foundation (WF) activities |
See domain_services/references/jobs/ for documentation on each executor component.
Next: GIS Walkthrough