system
tit.server.routes.system ¶
GET /api/system — one system snapshot (same payload as /ws/system).
The process keyword filter is copied from the PyQt system_monitor_tab.py
(that module is deleted with the Qt GUI; the server must not import it).
Only the keyword list is kept: the Qt tab's second branch — any python
process whose command line contains ti-, gui/, pre-process/,
simulator/, flex-search/ or ex-search/ — matched the legacy
script directories (ti-toolbox/gui/…) that no longer exist and would
match the server itself; it was dropped intentionally. The server's own
process is always excluded.
Terminated ¶
Bases: BaseModel
contracts/openapi.yaml's POST /api/system/terminate 200 body.
is_relevant_process ¶
Substring match of any keyword against "<name> <cmdline>" (lower-cased).
Source code in tit/server/routes/system.py
job_pid_owners ¶
pid -> (job_id, label) for every job whose runner process is alive.
Reads the job manager only if one already exists in this process: get_manager() builds
and starts a manager on first call, and a system snapshot must never be the thing that spins
up the job subsystem as a side effect of someone opening a monitoring page.
Children are covered too. A job's runner spawns charm/simnibs_python as descendants,
and those are the processes a person actually sees eating the CPU -- attributing only the
runner pid would leave every interesting row unowned, and ownership is what gates the UI's
stop affordance.
Source code in tit/server/routes/system.py
kernel_pid_owners ¶
pid -> (kernel_id, label) for every notebook kernel this server owns.
Source code in tit/server/routes/system.py
process_list ¶
The busiest processes plus how many there were, sorted by CPU (descending).
Two changes from the pre-2026-09-07 list, which returned only keyword-matched processes:
- Everything is listed, capped at :data:
PROCESS_LIMIT. A process table that hides the thing currently using the CPU because its name is not on a keyword list is not a process table. The keyword match survives asProcessInfo.relevant, so the UI can still say which rows are toolbox work. - Each row carries its owner (a job, a kernel, or this server). Only an owned row gets a
stop affordance in the UI, and stopping it goes through the job's own cancel path -- the
raw
POST /api/system/terminatestays as it was, keyword-gated.
The server's own process is still never listed (it is reported once, as own).
Source code in tit/server/routes/system.py
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | |
relevant_processes ¶
relevant_processes() -> list[ProcessInfo]
The pre-2026-09-07 list: keyword-matched processes only, busiest first.
Kept because POST /api/system/terminate's allowlist is defined in terms of it.
Source code in tit/server/routes/system.py
project_disk ¶
The filesystem the project volume is on; / when that cannot be read.
Source code in tit/server/routes/system.py
docker_disk ¶
The Docker root filesystem, or None when it is not visible from here.
load_average ¶
1/5/15-minute load average; [] on a platform without one.
kernel_count ¶
kernel_count() -> int
How many notebook kernels this server process owns right now.
Source code in tit/server/routes/system.py
own_process ¶
own_process() -> SelfProcessInfo | None
This server's own process — the parent of every job process.
Source code in tit/server/routes/system.py
net_io ¶
net_io() -> NetIO | None
Cumulative interface counters; the page shows the delta between two snapshots.
Source code in tit/server/routes/system.py
docker_warnings ¶
docker_warnings(health: DockerHealth) -> list[str]
The row the panel shows in the warning colour. Only conditions a person can act on.
Source code in tit/server/routes/system.py
docker_health ¶
docker_health(now: float | None = None) -> DockerHealth
Daemon reachability, docker system df, our own container and the siblings.
TTL-cached and hard-bounded, and every failure is reported rather than raised:
reachable: false with an error is a first-class answer, and the most useful thing the
panel could say at that moment. A monitoring page that goes down because the Docker daemon is
wedged has failed at the one job it had.
Source code in tit/server/routes/system.py
docker_siblings ¶
docker_siblings(now: float | None = None) -> list[ContainerInfo]
The sibling containers, from the same bounded, TTL-cached read as everything Docker.
snapshot ¶
Build one :class:SystemSnapshot (blocking; call from a thread).
Source code in tit/server/routes/system.py
start_scan ¶
start_scan() -> bool
Kick off a background scan unless one is already running. True if started.
Source code in tit/server/routes/system.py
storage_snapshot ¶
storage_snapshot(refresh: bool = False) -> ProjectStorage
The cached scan, refreshing in the background when it is stale or forced.
Never blocks on the walk. A project that has never been scanned answers with
zeros and scanning: true, and the page says "scanning…" rather than
"0 bytes", which would be a wrong number rather than a missing one.
Source code in tit/server/routes/system.py
terminate ¶
terminate(body: dict[str, Any]) -> Terminated
{pid} -> {pid, terminated}.
Deliberately narrow (ra_14 finding 5's own-process/pid-1 guard, applied
here rather than reused from :mod:tit.jobs.runner since this route has
no job/lock context at all -- it is a raw "kill this pid" button):
pidmust be a realintgreater than 1 (pid 1 is the container's init and, under some launchers, this very server's parent).- never the server's own pid (
os.getpid()). - must currently match :func:
is_relevant_process-- the same keyword allowlist the System page's process list is built from, so this can only ever terminate a process the UI already showed as toolbox-related, never an arbitrary pid a caller guesses.