ReUseX  0.0.5
3D Point Cloud Processing for Building Reuse
Loading...
Searching...
No Matches
JobScheduler.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// A process-wide pipeline job scheduler over many projects (spec 2026-10-08,
8// phase S2: ruxd serves several cases from one process).
9//
10// One JobScheduler owns a bounded pool of worker threads. Each project gets a
11// JobQueue from it — a FIFO of that project's jobs, with the same submit /
12// status / cancel / listener / writer-lock surface JobRunner always had. The
13// rules:
14//
15// * **At most one running job per queue.** A project's jobs run strictly in
16// submission order, one at a time, under that project's writer lock — two
17// stages writing the same `.rux` at once is never allowed.
18// * **At most `workers` running jobs in total.** The default is one: the GPU
19// is shared, and the stages are TBB-parallel internally already.
20// * **Round-robin between queues.** A free worker takes the next job from the
21// next queue in rotation that has work and is not already running, so a
22// project that queues ten jobs cannot starve one that queues one.
23//
24// PROGRESS is per job: the worker installs a core::ScopedProgressObserver for
25// the job it runs, so two jobs running at once on two workers each see only
26// their own stage's events (core/processing_observer.hpp explains why updates
27// made from pool threads still arrive).
28//
29// RECORDS go to an IJobStore at every state transition (JobStore.hpp): in
30// memory for `ruxd --local`, Postgres in server mode. Live progress stays here.
31
32#include "reusex/pipeline/JobStore.hpp"
33#include "reusex/pipeline/job_types.hpp"
34#include "reusex/pipeline/stages.hpp"
35
36#include <chrono>
37#include <cstddef>
38#include <filesystem>
39#include <memory>
40#include <optional>
41#include <string>
42#include <string_view>
43#include <vector>
44
45namespace reusex::pipeline {
46
50 std::size_t workers = 1;
51};
52
53class JobQueue;
54
57 public:
59 explicit JobScheduler(JobSchedulerOptions options = {},
60 std::shared_ptr<IJobStore> store = nullptr);
61
66
67 JobScheduler(const JobScheduler &) = delete;
69
74 std::unique_ptr<JobQueue>
75 make_queue(std::string key, std::filesystem::path project,
77
78 std::size_t workers() const noexcept;
79
81 std::size_t running_count() const;
82
84 std::shared_ptr<IJobStore> store() const;
85
86 struct Core;
87
88 private:
89 std::shared_ptr<Core> core_;
90};
91
93class JobQueue {
94 public:
101
102 JobQueue(const JobQueue &) = delete;
103 JobQueue &operator=(const JobQueue &) = delete;
104
105 const std::string &key() const noexcept;
106 const std::filesystem::path &project() const noexcept;
107
114 std::string submit(JobStage stage, std::string parameters = {},
115 std::string submitted_by = {});
116
119 bool cancel(std::string_view id);
120
122 std::optional<JobRecord> job(std::string_view id) const;
123
125 std::vector<JobRecord> jobs() const;
126
128 std::size_t queued_count() const;
129
131 bool is_busy() const;
132
136 bool has_work() const;
137
140 void wait_idle();
141
143 [[nodiscard]] WriterLease
144 try_acquire_writer(std::chrono::milliseconds timeout);
145
147 std::size_t add_listener(JobListener listener);
148 void remove_listener(std::size_t token);
149
150 struct State;
151
152 private:
153 friend class JobScheduler;
154 JobQueue(std::shared_ptr<JobScheduler::Core> core,
155 std::shared_ptr<State> state);
156
157 std::shared_ptr<JobScheduler::Core> core_;
158 std::shared_ptr<State> state_;
159};
160
161} // namespace reusex::pipeline
Persistence for job records. Implementations must be thread-safe.
Definition JobStore.hpp:35
One project's jobs on a JobScheduler. Every member is thread-safe.
JobQueue & operator=(const JobQueue &)=delete
void remove_listener(std::size_t token)
JobQueue(const JobQueue &)=delete
bool is_busy() const
True while one of this queue's jobs is executing.
WriterLease try_acquire_writer(std::chrono::milliseconds timeout)
Try to take the project's exclusive writer lock (see JobRunner).
friend class JobScheduler
Implementation detail.
std::size_t queued_count() const
Jobs of this queue still waiting to start.
const std::filesystem::path & project() const noexcept
bool cancel(std::string_view id)
Request cancellation (queued: cancelled now; running: cancel token set; terminal: no-op).
std::size_t add_listener(JobListener listener)
Register a listener for this queue's events. Returns a removal token.
const std::string & key() const noexcept
std::string submit(JobStage stage, std::string parameters={}, std::string submitted_by={})
Enqueue a stage run.
std::optional< JobRecord > job(std::string_view id) const
Snapshot of one of this queue's jobs, or nullopt if unknown or evicted.
void wait_idle()
Block until this queue has nothing queued, nothing running and every event delivered.
std::vector< JobRecord > jobs() const
Every retained job of this queue, most recently submitted first.
bool has_work() const
True while a job is queued or running, or an event is still being delivered to the listeners — read u...
~JobQueue()
Closes the queue: queued jobs are reported cancelled, a running job is asked to stop,...
std::shared_ptr< IJobStore > store() const
The store records are written to.
~JobScheduler()
Cancels every queued job (reported as cancelled), asks every running job to stop, and joins the worke...
std::size_t workers() const noexcept
JobScheduler & operator=(const JobScheduler &)=delete
JobScheduler(JobSchedulerOptions options={}, std::shared_ptr< IJobStore > store=nullptr)
std::size_t running_count() const
Jobs executing right now, across every queue.
std::unique_ptr< JobQueue > make_queue(std::string key, std::filesystem::path project, StageExecutor executor=default_stage_executor())
A new queue for project.
JobScheduler(const JobScheduler &)=delete
Wire form of one stored report PDF version — the ReportPdfVersion schema in ruxd's API contract (docs...
std::function< void(const JobEvent &)> JobListener
Listener callback.
JobStage
A pipeline stage that can be executed as a job.
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:148
std::unique_lock< std::timed_mutex > WriterLease
Exclusive right to write to a runner's project.
std::size_t workers
Worker threads, i.e.