Server mode¶
Pass --server <url> to make Visao act as a long-lived analysis
service. Clients exchange JSON requests and responses with the
server over NNG REQ/REP sockets. They manage workspaces and analyses
explicitly, and consume results as they arrive. The server keeps its
state between requests until you stop it.
Quick start¶
visao --server tcp://127.0.0.1:5500
The server prints Server is ready to receive incoming requests
and waits. A client then adds a workspace, attaches the files, starts
an analysis, polls its state, and destroys the analysis and the
workspace.
For programmatic clients see the libasp (Analysis Server Protocol) library. It wraps the request and response vocabulary in a typed C/C++ API and ships demo projects.
Architecture: actors¶
The server is built on a small in-tree actor framework
(frontend/userver/actor/) instead of a single thread + mutex.
Four cooperating components handle each request:
┌───────────────────┐ Request ┌──────────────────────────┐
│ NetworkReceiver │ ─────────► │ RequestProcessorActor │
│ (sockets, poll) │ │ (workspaces, analyses) │
└───────────────────┘ └────────────┬─────────────┘
│ spawn / cancel
▼
┌──────────────────────────┐
│ AnalysisWorker (per │
│ analysis, sacore_thread) │
└────────────┬─────────────┘
│ final Response
▼
┌──────────────────────────┐
│ ResponseSenderActor │
│ (per-pipe queue, ticked) │
└────────────┬─────────────┘
│ proto->send()
▼
network
NetworkReceiver owns the bound sockets. A single thread polls
proto->receive()(5 ms NNG timeout), deserialises the request, and posts arequest_envelopeto RequestProcessor.RequestProcessorActor owns the shared analysis state (
common_data: workspaces map, analyses map, FrontendInstance) privately. No other actor reads or writes those structures. Requests are processed strictly serially on the actor’s own thread. Each response goes out as aresponse_envelopeto ResponseSender.AnalysisWorker is spawned per
AnalysisStartrequest. It drives therunOneSubJobloop on its own thread, then emits aCheckStateresponse back through ResponseSender to notify the client.AnalysisDestroycancels and joins it.ResponseSenderActor holds one response queue for each pipe. NNG REQ/REP needs alternation (one REP for each client REQ). Therefore the actor drains a queue only when
proto->is_queue_readyreports that the pipe is ready. A tick of 5 ms checks the readiness again when no new response arrives.
Inter-actor communication is by value through std::queue
inboxes; there is no shared mutable state outside each actor.
Tuning flags¶
These options apply only in --server mode and are ignored in
console mode:
--server-max-analyses <N>Cap on concurrent
AnalysisWorkerthreads. Requests past the cap come back asError("Server analysis cap reached").0(default) means unlimited.--server-response-tick-ms <N>ResponseSender drain interval in milliseconds. Default
5. Lower means snappier reply when a pipe becomes ready; higher reduces wakeups when idle.--server-log-trafficPrint every received Request and emitted Response to stdout. Off by default. Useful for protocol debugging; noisy under load.
--server-graceful/--server-no-gracefulOn by default. When on, the server installs
SIGINT/SIGTERMhandlers that set an atomic shutdown flag. The main thread breaks out of its idle loop. Stack-unwind runs actor destructors in LIFO order (NetworkReceiver stops first → drains RequestProcessor → drains ResponseSender). When off, the default signal action kills the process immediately. Use this form for a hard stop in CI.
Binding multiple endpoints¶
Multiple --server arguments bind multiple endpoints on the same
process; they share the workspace/analysis state.
visao --server tcp://127.0.0.1:5500 \ --server tcp://10.0.0.5:5500
Lifecycle and cache¶
Toolchain detection runs once during FrontendInstance
construction. On a fresh CI image, run visao --update-toolchains
before you launch the server. The first client request then uses the
warm cache.
The server holds workspaces and analyses in memory for the lifetime
of the process. Each run issues new Workspace and Analysis
IDs. For persistence, use the optional DAL (Database Access Layer)
integration. DAL journals analysis results to MongoDB, and the
#ifdef ENABLE_DAL switch selects that backend at build time.
libasp¶
Hand-rolling JSON requests gets old fast. For real applications use libasp (Analysis Server Protocol library), which gives you a typed C/C++ client API, request/response factories, and a small event loop. The ASP documentation in the asp subproject contains demo projects and the full protocol description.