Integrated Variant¶
The optional webatm_integrated package used by the
integrated build. It is wired into the core app
only when WEBATM_INTEGRATED=1.
webatm_integrated¶
webatm_integrated ¶
Provide the WebATM integrated extensions.
Shipped ONLY in the webatm-integrated build variant. Adds BlueSky server
lifecycle control (start/stop/restart/kill), live, in-order log streaming of the
bluesky --headless process tree to the web UI, and -- because BlueSky runs in
this same container -- pre-wires WebATM's file management directly to BlueSky's
own scenario / plugins / output directories (no manual base-path step).
The core webatm package never imports this package. It is wired in through a
single env-guarded hook in WebATM.app.create_app that calls register
only when WEBATM_INTEGRATED=1 and this package is installed.
LogStreamer ¶
Buffer process output and broadcast it as ordered, batched events.
Initialize the streamer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
socketio
|
SocketIO
|
Instance used to emit batches. |
required |
max_history
|
int
|
Maximum lines retained for history replay. |
2000
|
batch_ms
|
int
|
Delay in milliseconds used to coalesce a batch. |
100
|
batch_max
|
int
|
Maximum lines per emitted batch chunk. |
200
|
Source code in WebATM-integrated/webatm_integrated/log_streamer.py
feed_line ¶
Ingest one output line, assign its order, and schedule a flush.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
line
|
str
|
The process output line to broadcast. |
required |
Source code in WebATM-integrated/webatm_integrated/log_streamer.py
history ¶
Return a snapshot of buffered lines for late-joining clients.
Returns:
| Type | Description |
|---|---|
list[dict]
|
Buffered items with |
Source code in WebATM-integrated/webatm_integrated/log_streamer.py
on_process_exit ¶
Emit an end-of-stream marker when the server process exits.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
return_code
|
int
|
Exit code of the BlueSky server process. |
required |
Source code in WebATM-integrated/webatm_integrated/log_streamer.py
BlueSkyProcessManager ¶
BlueSkyProcessManager(
on_line: Callable[[str], None] | None = None,
on_exit: Callable[[int], None] | None = None,
spawn: Callable | None = None,
cmd: list[str] | None = None,
)
Thread-safe lifecycle manager for the bluesky --headless process tree.
Tracks only the parent process; signals (stop/kill) address the whole process group so node children are reaped together with the server.
Initialize the process manager.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
on_line
|
Callable[[str], None] | None
|
Callback invoked with each output line of the process tree (newline stripped). |
None
|
on_exit
|
Callable[[int], None] | None
|
Callback invoked with the return code when the server process exits. |
None
|
spawn
|
Callable | None
|
Spawn primitive for the reader task (e.g.
|
None
|
cmd
|
list[str] | None
|
Command to launch; defaults to
|
None
|
Source code in WebATM-integrated/webatm_integrated/process_manager.py
start ¶
Spawn the headless server (in its own process group) and a reader.
The process is started in a new session with merged, line-buffered
stdout/stderr so the reader receives one ordered stream for the
server and all node children. A no-op if the server is already
running. If a concurrent :meth:stop is mid-shutdown, waits for it
to finish and then starts a fresh server instead of reporting the
doomed process as "already running".
Returns:
| Type | Description |
|---|---|
dict
|
Result with |
Source code in WebATM-integrated/webatm_integrated/process_manager.py
stop ¶
Signal the whole process group, escalating to SIGKILL if needed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sig
|
int
|
Signal sent to the process group first. |
SIGTERM
|
escalate_after
|
float
|
Seconds to wait for exit before force-killing the group with SIGKILL. |
5.0
|
Returns:
| Type | Description |
|---|---|
dict
|
Result with |
Source code in WebATM-integrated/webatm_integrated/process_manager.py
kill ¶
Force-kill the whole process group immediately (no graceful wait).
Returns:
| Type | Description |
|---|---|
dict
|
Result with |
Source code in WebATM-integrated/webatm_integrated/process_manager.py
restart ¶
Stop the current tree (if any) and start a fresh one.
Returns:
| Type | Description |
|---|---|
dict
|
The |
Source code in WebATM-integrated/webatm_integrated/process_manager.py
status ¶
Report whether the server is running, with its pid and state.
Returns:
| Type | Description |
|---|---|
dict
|
Result with |
Source code in WebATM-integrated/webatm_integrated/process_manager.py
register ¶
Wire the integrated features into an existing WebATM app.
Called by WebATM.app.create_app when WEBATM_INTEGRATED=1. Points
file management at BlueSky's fixed working directory, creates the process
manager and log streamer (stashed on app), registers the integrated
REST routes and Socket.IO handlers, reaps the BlueSky process group on
worker exit, and — on the first boot only (claim_first_boot()) —
schedules the background auto-start (disable with WEBATM_AUTO_START=0).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
app
|
Flask
|
Flask application instance. |
required |
socketio
|
SocketIO
|
Flask-SocketIO instance
( |
required |
session_manager
|
SessionManager
|
Core session manager (accepted for forward-compat; currently unused). |
None
|
bluesky_proxy
|
BlueSkyProxy
|
Core proxy, used for the first-boot auto-connect. |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
The created |
Source code in WebATM-integrated/webatm_integrated/__init__.py
webatm_integrated.auto_start¶
webatm_integrated.auto_start ¶
Auto-start the bundled BlueSky server and connect the proxy on first boot.
Integrated build only: BlueSky runs in the same container, so on start-up we
spawn the bluesky --headless process tree and, once its ports accept
connections, run the same connect sequence as the manual /api/server/config
route. The user lands on a live, already-connected map. If a manual connect
wins the race, auto-start stands down (see connect_proxy_when_ready).
Opt out with WEBATM_AUTO_START=0. The core webatm package never imports
this module; it is reached only via webatm_integrated.register (env-guarded
on WEBATM_INTEGRATED=1).
auto_start_enabled ¶
Report whether to auto-start BlueSky and auto-connect on boot.
On by default; set WEBATM_AUTO_START=0 to disable.
Returns:
| Type | Description |
|---|---|
bool
|
True unless the |
Source code in WebATM-integrated/webatm_integrated/auto_start.py
claim_first_boot ¶
Atomically claim the one-shot auto-start for this boot.
Creates the marker file with O_CREAT | O_EXCL so only the first caller
per boot wins — a replaced gunicorn worker re-running register() stands
down instead of resurrecting a manually-stopped server. The default marker
lives on tmpfs so it clears on a fresh container start.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
marker_path
|
str | None
|
Marker file location. Defaults to
|
None
|
Returns:
| Type | Description |
|---|---|
bool
|
True for the first caller to create the marker file, False
thereafter. If the marker cannot be created at all (e.g. no
|
Source code in WebATM-integrated/webatm_integrated/auto_start.py
schedule_auto_start ¶
Run the auto-start sequence on a background task.
Backgrounded so register() (which runs during app creation) returns
immediately: waiting for BlueSky's ports can take several seconds on a cold
start, and we must not block the worker from beginning to serve requests.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
socketio
|
SocketIO
|
Socket.IO instance whose
|
required |
manager
|
BlueSkyProcessManager
|
Process manager used to start the BlueSky server. |
required |
bluesky_proxy
|
BlueSkyProxy | None
|
Core proxy to connect once BlueSky is ready, or None to skip the auto-connect. |
required |
Source code in WebATM-integrated/webatm_integrated/auto_start.py
connect_proxy_when_ready ¶
connect_proxy_when_ready(
bluesky_proxy,
*,
host: str | None = None,
ready_timeout: float = 60.0,
poll_interval: float = 0.5,
is_port_listening: Callable[..., bool] | None = None,
register_subscribers: Callable[..., None] | None = None,
get_proxy: Callable[[], object] | None = None,
lock: AbstractContextManager | None = None,
sleep: Callable[[float], None] | None = None,
) -> bool
Wait for BlueSky to accept connections, then connect the WebATM proxy.
Polls BlueSky's command/data ports until one is listening (or the timeout
elapses), then performs the same start_client → register_subscribers
sequence as the manual /api/server/config route. The connect step runs
under the shared WebATM.proxy.connect_lock and stands down if a manual
connect replaced the global proxy during the port wait — connecting the
stale boot-time proxy would leave a second, subscriber-less ZMQ client
alive to broadcast a bogus disconnect later.
The collaborators are injectable so this can be unit-tested without a real BlueSky server or wall-clock delays.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
bluesky_proxy
|
BlueSkyProxy
|
Core proxy to connect. |
required |
host
|
str | None
|
BlueSky server host. Defaults to the proxy's
|
None
|
ready_timeout
|
float
|
Maximum seconds to wait for a port to listen. |
60.0
|
poll_interval
|
float
|
Seconds to sleep between port probes. |
0.5
|
is_port_listening
|
Callable | None
|
Port probe |
None
|
register_subscribers
|
Callable | None
|
Subscriber-registration hook;
defaults to |
None
|
get_proxy
|
Callable | None
|
Returns the current global proxy;
defaults to |
None
|
lock
|
AbstractContextManager | None
|
Lock held around the connect
step; defaults to |
None
|
sleep
|
Callable | None
|
Sleep function; defaults to |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
True if the proxy connect succeeded, False if BlueSky never came up in time, the connect raised, or a manual connect won the race. |
Source code in WebATM-integrated/webatm_integrated/auto_start.py
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 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 | |
webatm_integrated.process_manager¶
webatm_integrated.process_manager ¶
BlueSky headless server process manager.
Owns the lifecycle of the bluesky --headless process tree: the headless
server plus every node child process it spawns. On POSIX, BlueSky spawns node
children as ordinary subprocesses that inherit the parent's stdout/stderr and
live in the parent's process group, so:
- a single merged pipe on the parent captures the server and all node-child output, already interleaved in order; and
- launching the parent in its own session (
start_new_session=True) lets us reap the entire tree with oneos.killpg.
BlueSkyProcessManager ¶
BlueSkyProcessManager(
on_line: Callable[[str], None] | None = None,
on_exit: Callable[[int], None] | None = None,
spawn: Callable | None = None,
cmd: list[str] | None = None,
)
Thread-safe lifecycle manager for the bluesky --headless process tree.
Tracks only the parent process; signals (stop/kill) address the whole process group so node children are reaped together with the server.
Initialize the process manager.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
on_line
|
Callable[[str], None] | None
|
Callback invoked with each output line of the process tree (newline stripped). |
None
|
on_exit
|
Callable[[int], None] | None
|
Callback invoked with the return code when the server process exits. |
None
|
spawn
|
Callable | None
|
Spawn primitive for the reader task (e.g.
|
None
|
cmd
|
list[str] | None
|
Command to launch; defaults to
|
None
|
Source code in WebATM-integrated/webatm_integrated/process_manager.py
start ¶
Spawn the headless server (in its own process group) and a reader.
The process is started in a new session with merged, line-buffered
stdout/stderr so the reader receives one ordered stream for the
server and all node children. A no-op if the server is already
running. If a concurrent :meth:stop is mid-shutdown, waits for it
to finish and then starts a fresh server instead of reporting the
doomed process as "already running".
Returns:
| Type | Description |
|---|---|
dict
|
Result with |
Source code in WebATM-integrated/webatm_integrated/process_manager.py
stop ¶
Signal the whole process group, escalating to SIGKILL if needed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sig
|
int
|
Signal sent to the process group first. |
SIGTERM
|
escalate_after
|
float
|
Seconds to wait for exit before force-killing the group with SIGKILL. |
5.0
|
Returns:
| Type | Description |
|---|---|
dict
|
Result with |
Source code in WebATM-integrated/webatm_integrated/process_manager.py
kill ¶
Force-kill the whole process group immediately (no graceful wait).
Returns:
| Type | Description |
|---|---|
dict
|
Result with |
Source code in WebATM-integrated/webatm_integrated/process_manager.py
restart ¶
Stop the current tree (if any) and start a fresh one.
Returns:
| Type | Description |
|---|---|
dict
|
The |
Source code in WebATM-integrated/webatm_integrated/process_manager.py
status ¶
Report whether the server is running, with its pid and state.
Returns:
| Type | Description |
|---|---|
dict
|
Result with |
Source code in WebATM-integrated/webatm_integrated/process_manager.py
webatm_integrated.log_streamer¶
webatm_integrated.log_streamer ¶
Live, in-order log streaming of the BlueSky process tree to web clients.
A single server-wide stream (one subprocess) is broadcast to all connected
browsers over the server_log Socket.IO event. Ordering is guaranteed by a
monotonic sequence number assigned under a lock at ingest, before any async
hop. Bursts (for example, creating many nodes at once) are coalesced into
batches so a flood of lines cannot overwhelm Socket.IO.
Every payload also carries a per-streamer stream id. Sequence numbers
restart at 1 whenever the backend (and with it this streamer) is replaced --
a container restart, a recycled gunicorn worker -- while an open browser tab
keeps the old session's seqs and de-duplicates on them. Without the stream id
the new boot's lines would collide and be silently dropped client-side.
LogStreamer ¶
Buffer process output and broadcast it as ordered, batched events.
Initialize the streamer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
socketio
|
SocketIO
|
Instance used to emit batches. |
required |
max_history
|
int
|
Maximum lines retained for history replay. |
2000
|
batch_ms
|
int
|
Delay in milliseconds used to coalesce a batch. |
100
|
batch_max
|
int
|
Maximum lines per emitted batch chunk. |
200
|
Source code in WebATM-integrated/webatm_integrated/log_streamer.py
feed_line ¶
Ingest one output line, assign its order, and schedule a flush.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
line
|
str
|
The process output line to broadcast. |
required |
Source code in WebATM-integrated/webatm_integrated/log_streamer.py
history ¶
Return a snapshot of buffered lines for late-joining clients.
Returns:
| Type | Description |
|---|---|
list[dict]
|
Buffered items with |
Source code in WebATM-integrated/webatm_integrated/log_streamer.py
on_process_exit ¶
Emit an end-of-stream marker when the server process exits.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
return_code
|
int
|
Exit code of the BlueSky server process. |
required |
Source code in WebATM-integrated/webatm_integrated/log_streamer.py
webatm_integrated.bluesky_paths¶
webatm_integrated.bluesky_paths ¶
BlueSky file-management path wiring for the integrated build.
In the integrated variant BlueSky runs inside the same container, and a
pip-installed BlueSky keeps its working directory at ~/bluesky (see
BlueSky's pathfinder). This module points WebATM's existing
file-management routes (/api/bluesky/...) at that directory and locks
them there, replacing the standalone build's manual "configure base path"
step, so uploads and browsing always land exactly where the running server
reads them. Only reached via webatm_integrated.register (env-guarded on
WEBATM_INTEGRATED=1); the core webatm package never imports it.
resolve_bluesky_workdir ¶
Return BlueSky's working directory (where scenario/plugins/output live).
Deliberately mirrors the pip-package rule (~/bluesky) instead of
exposing a setting, so WebATM and the BlueSky server can never point at
different directories.
Returns:
| Type | Description |
|---|---|
Path
|
BlueSky's working directory ( |
Source code in WebATM-integrated/webatm_integrated/bluesky_paths.py
configure_file_management ¶
Pre-configure WebATM's file-management routes for the integrated build.
Sets app.bluesky_base_path -- the same attribute the standalone
/api/bluesky/configure-base-path route sets, so every existing file
route works unchanged -- and locks it (bluesky_base_path_locked) so
that route refuses to repoint it. The managed subdirectories are
best-effort created so the UI can browse and upload even before the
BlueSky server's first start.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
app
|
Flask
|
Flask application instance. |
required |
Returns:
| Type | Description |
|---|---|
str
|
The configured base path (BlueSky's working directory). |
Source code in WebATM-integrated/webatm_integrated/bluesky_paths.py
webatm_integrated.routes¶
webatm_integrated.routes ¶
REST control routes for the integrated BlueSky server.
Namespaced under /api/integrated/ so they cannot collide with core routes
and are simply absent from the default build.
register_integrated_routes ¶
Register server lifecycle-control routes on the Flask app.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
app
|
Flask
|
Flask application instance. |
required |
manager
|
BlueSkyProcessManager
|
Controls the bundled server. |
required |
Source code in WebATM-integrated/webatm_integrated/routes.py
webatm_integrated.socket_handlers¶
webatm_integrated.socket_handlers ¶
Socket.IO handlers for the integrated build.
Provides live-log history replay for late-joining clients. The lifecycle
actions themselves are REST-only (see :mod:.routes).
register_integrated_socket_handlers ¶
Register the integrated build's Socket.IO event handlers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
socketio
|
SocketIO
|
The Flask-SocketIO instance. |
required |
streamer
|
LogStreamer
|
Holds the server-log history. |
required |