Session Host Service
The Session Host (started as a backend with webstream.exe -backend) is the private application server — the unit of compute that scales with concurrent sessions. It manages a pool of Windows RDP sessions, launches a Streamer inside each one, and registers itself with the Gateway so traffic can be routed to it.
Function
- Session pool management. Provisions and recycles Windows pool accounts (e.g.
webs01,webs02), creating an RDP session per user connection and tearing it down — with profile cleanup and NTFS ACL enforcement — when the session ends. - Streamer launch. Each RDP session runs its own
webstream.exestreamer instance, launched at session logon; the Session Manager hands it its session UUID and command line over the/controlWebSocket protocol. - Connection brokering. Answers
/getConnection(proxied from the gateway) by allocating a pool session and returning the streamer's port so the browser's WebSockets can be proxied through. - Gateway registration. Registers on startup, heartbeats every 10 seconds with live capacity and load figures, and unregisters on shutdown.
- Static content. Serves the
httpdocsweb client over plain HTTP on the private network (the gateway terminates SSL).
Ports and endpoints
| Listener | Port | Purpose |
|---|---|---|
| HTTP | gateway.backend.advertisedUrl port (default 9005) | Health checks, /getConnection, static web client. Port 9005 avoids conflicts: Gateway = 9000, Streamers = 9010/9020/… |
In standalone Session Manager mode (-sm, without a gateway) the service also opens a /control WebSocket on basePortNumber (9000) and HTTP on 9001. Production deployments use -backend, where the gateway proxies WebSockets directly to streamers instead.
Message contracts
Outbound — to the Gateway
| Endpoint | Method | Frequency | Payload |
|---|---|---|---|
/gateway/register | POST | Startup (after a local /health self-check; retried every 30 s, up to 10 times) | { serverUrl, maxSessions, instanceType, ec2InstanceId, tags[], capabilities[], version } |
/gateway/heartbeat | POST | Every 10 s (config heartbeatInterval) | { serverUrl, status, activeSessions, maxSessions, instanceType, tags[], cpuUsage, memoryUsage, timestamp } |
/gateway/unregister | POST | Shutdown | { serverUrl } |
Inbound — from the Gateway
| Endpoint | Method | Frequency | Purpose / payload |
|---|---|---|---|
/health | GET | Every 1–10 s (gateway health monitor) | Returns { status, timestamp, sessions: { total, active, available }, uptime }. |
/getConnection | GET | Per workspace launch / reconnect | Requires X-Session-ID; optional ?width=&height=. Allocates a pool session and returns the streamer connection details. Workspace context arrives in the injected X-Workspace-*, X-App-*, and X-Policy-JSON headers. |
| Static paths | GET | Per page load | Web client assets from serverHttpPath. |
Local — Session Manager ↔ Streamer (WebSocket text protocol)
| Message | Direction | When |
|---|---|---|
REQUEST_SESSION_INFO:{username} | Streamer → Session Manager | Streamer startup inside a new RDP session. |
SESSION_INFO:{sessionUuid}|{commandLineParams} | Session Manager → Streamer | Reply carrying the session identity and launch parameters. |
FILE_UPLOAD_COMPLETE:{dialogGuid}|{filePath} | Session Manager → Streamer | Notifies a waiting headless file dialog that an upload has landed. |
Session start queue
Starting a session is disk-intensive: profile, registry, and hive preparation followed by an RDP logon that loads NTUSER.DAT. Running several of these at once causes disk-IOPS contention that can thrash competing starts and destabilise sessions already running, so the start phase is strictly serialised through a gate with capacity fixed at 1 (by design, not configurable).
- Non-blocking.
/getConnectionnever waits on the gate. A queued session is registered immediately in stateQueuedForPrepand the browser polls, showing preparing, until its FIFO turn completes. The client is told its queue position. - Bounded. Beyond
maxQueuedStartsa new launch is rejected withSTART_QUEUE_FULL— an honest “try again later” beats promising an unboundedly long serial wait. - Abandoned waiters. A queued start whose browser stops polling for
abandonSeconds(tab closed, navigated away) is cancelled rather than burning a gate slot on a session nobody is waiting for. - Watchdog. A wedged head-of-queue start is failed after
prepWatchdogSecondsand the gate released, so one stuck logon cannot stall every start on the host. - Settle window. After a successful logon the gate is held for
settleSecondswhile Windows spins up per-user services and the shell at high CPU, smoothing resources before the next start begins.
The queue is tuned by the optional <sessionStartQueue> element inside <webstreamSettings> in app.config.xml. If the element is missing, the defaults below apply.
| Property | Default | Purpose |
|---|---|---|
prepWatchdogSeconds | 120 | Maximum time one start may hold the gate before it is failed and the gate released. Clamped to a minimum of 30. |
maxQueuedStarts | 10 | Maximum starts in the queue (including the one holding the gate); beyond this, launches return START_QUEUE_FULL. 0 = unlimited. |
abandonSeconds | 30 | Cancel a queued start whose browser has not polled for this long. 0 = disabled. |
settleSeconds | 5 | Hold the gate this long after a successful logon before the next start. Capped at 60. |
The start queue is per host. When the whole cluster has no free session slots, the Gateway answers new launches with capacity_reached instead of queuing them — and, where auto-scaling is configured, brings up another session host.
Configuration
| Property | Purpose |
|---|---|
gateway.backend.gatewayUrl | The gateway to register with (HTTPS; the gateway terminates SSL). |
gateway.backend.advertisedUrl | This host's own URL as the gateway should reach it (HTTP, private network, default port 9005). |
gateway.backend.heartbeatInterval | Heartbeat period in seconds (default 10). |
gateway.backend.maxSessions | Session capacity advertised to the gateway's load balancer. |
webstreamSettings.serverMaxSessionCount | Size of the local RDP session pool. |
webstreamSettings.serverSessionUsername / serverSessionPwd | Base pool account credentials (accounts webs01… derive from these). |
webstreamSettings.basePortNumber | Base for the per-session streamer port formula (base + userNumber × 10). |
webstreamSettings.serverHttpPath | Root of the static web client (httpdocs). |
webstreamSettings.sessionStartQueue | Serial session-start queue tuning — see Session start queue above. |
-tags gpu,autocad (command line) | Capability tags advertised at registration, used for tag-aware workspace placement. |
filesystemRestrictions, profileCleanup | Session hygiene applied at pool-account recycle: NTFS DENY ACLs, registry restore, profile purge. |
Aligned settings on peer services
- The gateway's
healthCheck.timeout(≥ 6 s recommended) andfailureThreshold(≥ 3) must tolerate this host answering probes slowly during heavy login provisioning, or it will be flapped to Unreachable and workspace launches will fail. - Streamers on this host read the same
gateway.backend.gatewayUrlfor their 15-second licence check-ins. metricsandactivityLoggingsections on this host determine what its streamers report to the Metrics Engine.
For Backend Only installer steps, session-pool sizing, and AWS port ranges, see Installing Backend Nodes and AWS Security Groups and Ports.