ReUseX  0.0.5
3D Point Cloud Processing for Building Reuse
Loading...
Searching...
No Matches
JobRunner.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 Povl Filip Sonne-Frederiksen
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#pragma once
6
7// In-process pipeline job runner (#265, Phase 1).
8//
9// Owns a FIFO queue of stage runs and a single worker thread, bridges the
10// global core::IProgressObserver singleton into per-job progress events, and
11// exposes a submit / status / cancel surface that both `rux gui` (today) and
12// ruxd (Phase 6) can put behind the same HTTP contract.
13//
14// WHY ONE WORKER: progress reporting goes through the process-global observer
15// registered with core::set_progress_observer(). Two stages running
16// concurrently would interleave into a single observer with no way to tell
17// their events apart, so jobs are serialized. The stages themselves are
18// TBB-parallel internally and already saturate the machine.
19//
20// THREAD SAFETY: every public member is safe to call from any thread. The
21// ProjectDB instance used to execute a job is created and destroyed on the
22// worker thread and never escapes it — ProjectDB itself is not thread-safe.
23//
24// WRITER EXCLUSION: the runner also owns the project's *writer lock* (see
25// try_acquire_writer). The worker holds it for the whole execution of a stage,
26// so anything else that wants to write to the same `.rux` — the GUI's editor
27// endpoints, for instance — can take the same lock and be genuinely exclusive
28// with the pipeline rather than merely hoping sqlite sorts it out.
29
30#include "reusex/core/stages.hpp"
31#include "reusex/pipeline/stages.hpp"
32
33#include <chrono>
34#include <cstddef>
35#include <cstdint>
36#include <filesystem>
37#include <functional>
38#include <memory>
39#include <mutex>
40#include <optional>
41#include <string>
42#include <string_view>
43#include <vector>
44
46
60
62std::string_view to_string(JobStatus status);
63
65std::optional<JobStatus> parse_job_status(std::string_view name);
66
69
71std::string iso8601_utc_now();
72
74struct JobRecord {
75 std::string id;
78 std::string parameters;
79 std::string error;
80 std::string submitted_at;
81 std::string started_at;
82 std::string finished_at;
83 bool cancel_requested = false;
84
87 size_t progress_current = 0;
88 size_t progress_total = 0;
89
94 std::string result_summary;
95 std::vector<StageArtifact> result_outputs;
96};
97
100struct JobEvent {
110 uint64_t sequence = 0;
111
118
120 std::string timestamp;
122};
123
125std::string_view to_string(JobEvent::Type type);
126
129using JobListener = std::function<void(const JobEvent &)>;
130
136using WriterLease = std::unique_lock<std::timed_mutex>;
137
151 size_t max_terminal_jobs = 256;
152};
153
174 public:
178 explicit JobRunner(std::filesystem::path project,
180
182 JobRunner(std::filesystem::path project, StageExecutor executor,
183 JobRunnerOptions options);
184
187
188 JobRunner(const JobRunner &) = delete;
189 JobRunner &operator=(const JobRunner &) = delete;
190
192 const std::filesystem::path &project() const noexcept;
193
197 std::string submit(JobStage stage, std::string parameters = {});
198
204 bool cancel(std::string_view id);
205
212 std::optional<JobRecord> job(std::string_view id) const;
213
218 std::vector<JobRecord> jobs() const;
219
221 size_t queued_count() const;
222
224 bool is_busy() const;
225
228 void wait_idle();
229
248 [[nodiscard]] WriterLease
249 try_acquire_writer(std::chrono::milliseconds timeout);
250
252 size_t add_listener(JobListener listener);
253
255 void remove_listener(size_t token);
256
257 private:
258 class Impl;
259 std::unique_ptr<Impl> impl_;
260};
261
262} // namespace reusex::pipeline
size_t queued_count() const
Number of jobs still waiting to start.
std::string submit(JobStage stage, std::string parameters={})
Enqueue a stage run.
bool is_busy() const
True while a job is executing.
size_t add_listener(JobListener listener)
Register a listener. Returns a token for remove_listener().
void wait_idle()
Block until the queue is empty and no job is running.
JobRunner(const JobRunner &)=delete
JobRunner(std::filesystem::path project, StageExecutor executor, JobRunnerOptions options)
As above, with an explicit job-store policy.
const std::filesystem::path & project() const noexcept
The project every job of this runner targets.
~JobRunner()
Requests cancellation of anything in flight and joins the worker.
std::vector< JobRecord > jobs() const
Snapshot of every retained job, most recently submitted first.
void remove_listener(size_t token)
Unregister a listener. Safe to call with an unknown token.
JobRunner(std::filesystem::path project, StageExecutor executor=default_stage_executor())
WriterLease try_acquire_writer(std::chrono::milliseconds timeout)
Try to take the project's exclusive writer lock, giving up after timeout.
bool cancel(std::string_view id)
Request cancellation.
std::optional< JobRecord > job(std::string_view id) const
Snapshot of one job, or nullopt if the id is unknown or evicted.
JobRunner & operator=(const JobRunner &)=delete
std::function< void(const JobEvent &)> JobListener
Listener callback.
std::optional< JobStatus > parse_job_status(std::string_view name)
Parse a canonical status name. Returns nullopt for an unknown name.
std::string_view to_string(JobStatus status)
Canonical lower-case status name used on the wire.
JobStage
A pipeline stage that can be executed as a job.
Definition stages.hpp:42
@ clouds
back-project sensor frames into "cloud" + "normals"
Definition stages.hpp:43
StageExecutor default_stage_executor()
The executor that actually runs the pipeline (a thin wrap of run_stage).
std::function< StageResult(const StageContext &)> StageExecutor
Stage execution strategy.
Definition stages.hpp:144
std::string iso8601_utc_now()
UTC timestamp in ISO-8601 form (e.g. "2026-09-08T11:22:33Z").
JobStatus
Lifecycle of a submitted job.
Definition JobRunner.hpp:53
std::unique_lock< std::timed_mutex > WriterLease
Exclusive right to write to a runner's project.
bool is_terminal(JobStatus status)
True for statuses a job can never leave.
One notification about a job.
std::string timestamp
ISO-8601 UTC.
uint64_t sequence
Monotonic emission order, starting at 1.
@ started
Picked up by the worker.
@ progress
Progress counters changed (throttled).
@ submitted
Accepted onto the queue.
@ finished
Reached a terminal status.
A job as reported by the runner. Snapshot; never a live view.
Definition JobRunner.hpp:74
std::string submitted_at
ISO-8601 UTC.
Definition JobRunner.hpp:80
size_t progress_total
0 = indeterminate.
Definition JobRunner.hpp:88
std::string started_at
ISO-8601 UTC; empty while queued.
Definition JobRunner.hpp:81
std::string error
Failure reason; empty unless status == failed.
Definition JobRunner.hpp:79
std::string parameters
JSON object as submitted ("" = defaults).
Definition JobRunner.hpp:78
core::Stage progress_stage
Live progress, mirrored from the stage's core::ProgressObserver.
Definition JobRunner.hpp:86
std::vector< StageArtifact > result_outputs
Definition JobRunner.hpp:95
std::string finished_at
ISO-8601 UTC; empty until terminal.
Definition JobRunner.hpp:82
std::string result_summary
The stage's own summary of what it produced, and the artifacts it wrote.
Definition JobRunner.hpp:94
std::string id
Opaque server-generated identifier (GUID).
Definition JobRunner.hpp:75
Tuning knobs for the job store.
size_t max_terminal_jobs
Terminal (succeeded/failed/cancelled) jobs retained before the oldest are dropped.