Control Plane And Service Ops
Purpose
The control-plane, control-agent, and control-panel tools give local and LAN operators a shared way to start services, inspect health, register live instances, allocate game servers, and debug handoff or zone-transfer routing.
The ownership split is simple:
- The control-plane owns fleet records, allocation decisions, handoff records, and transfer activation state.
- The control-agent owns process supervision on one host.
- The control-panel polls services and agents, starts or stops local and remote managed services, and signs internal operator requests.
Startup Order
Start infrastructure first. The control-plane requires Redis for readiness. Login and game services require their configured database, Redis, and control-plane connection.
For managed local startup, use this order:
- Control-plane
- Login server
- Game server
Login and game both depend on the control-plane. The local panel process launcher waits for each dependency's /ready endpoint before starting the next service and stops services in the reverse order.
The control-agent may be started before or after the control-plane because it is only a host supervisor. When using an agent to start remote services, start control-plane before login or game; the agent API starts the requested service directly and does not apply the panel's dependency order for you.
The control-panel can start at any time. Until services are reachable, it will show polling errors rather than owning recovery.
Allocation Ownership
The control-plane exposes protected registry and allocator routes for instances, presence, game assignment, zone-transfer assignment, handoff prepare/preflight/consume/redirect, and transfer activation confirmation/status.
Services publish and delete InstanceRecord data through the control-plane. Redis stores instance registry entries with a short TTL, so stale instances naturally fall out when services stop heartbeating or deregister.
Game allocation loads current game instance records, keeps the latest incarnation per placement, rejects records that do not match realm or zone, rejects draining or full targets, rejects unavailable zone pressure, and requires healthy allocation endpoints. When more than one target is valid, the allocator prefers region match, healthier endpoints, healthier zone pressure, already populated zones, tighter available capacity, and stable endpoint ordering.
Zone-transfer allocation requires a canonical scenes/*.scene target, excludes the current instance, resolves hosted zone scene data from workspace assets, checks the requested entry point, and only returns a target that passes admission. Invalid scene references return a bad request; no healthy target returns service unavailable.
Do not make the agent or panel the authority for allocation. They can start processes and send requests, but the control-plane is the allocator.
Remote Process Management
The control-agent serves:
GET /healthGET /readyGET /v1/servicesGET /v1/services/{service}/logsPOST /v1/services/{service}/startPOST /v1/services/{service}/stopPOST /v1/services/{service}/restart
Set AETHER_AGENT_WORKSPACE_ROOT to the workspace the agent should build and run from. AETHER_AGENT_BIND defaults to 0.0.0.0:7300; AETHER_AGENT_NAME defaults to the host name; AETHER_AGENT_TOKEN enables bearer-token auth. Do not expose a LAN agent without a token and firewall rules.
On start, the agent runs cargo build -p <service package> in the workspace, launches the debug service binary, records child pid and start time, and streams stdout/stderr into an in-memory log buffer capped at 500 lines. On stop, it tries the shared process-tree terminator first, then falls back to killing the child process. Status refresh records process exits and process status errors in the service snapshot.
Configure environment on the host that runs the service. Remote agent start requests select the service; they do not carry a full per-service environment payload from the panel.
Internal Request Signing
All protected control-plane APIs require signed internal-service headers. The accepted identities are login-server, game-server, and control-panel.
The signature covers method, path and query, internal service identity, timestamp, nonce, and body SHA-256. The timestamp skew window is 300 seconds. Nonces are registered in Redis under the control-plane nonce scope with SET ... EX ... NX; replayed nonces are rejected.
Common failure modes:
- Missing, stale, disallowed, or bad signatures return unauthorized.
- Body read failures return bad request.
- Redis failure during nonce registration returns internal server error.
- Client helpers reject non-HTTPS control-plane URLs unless insecure HTTP is explicitly allowed.
- Public or LAN deployments must not use the default development
AETHER_CONTROL_AUTH_SECRET.
The panel uses the shared signing helpers for control-plane reads and internal JSON posts, so panel requests should fail the same way login and game server requests fail.
Panel Polling
The control-panel default poll interval is 3 seconds. Polling runs with a blocking HTTP client and a 2 second timeout.
Each poll:
- Probes service health, readiness, info, and metrics according to the service descriptor.
- Reads control-plane instances and presence through signed GET requests.
- Polls each configured control-agent at
/v1/services, using bearer auth when the agent config has a token. - Attempts external endpoint discovery for the network status panel.
A service reachability error is shown only when that service is expected to support health or readiness and both probes fail. A signed control-plane read failure is reported separately as a monitor error for instances or presence.
Health And Readiness
Control-plane /health is an unconditional service liveness response. Control-plane /ready pings Redis and fails if Redis cannot be reached or does not return PONG.
Control-agent /health is an unconditional liveness response. Control-agent /ready fails if the configured workspace root no longer exists. Agent startup also fails immediately when the workspace root is missing.
Service start failures usually show in the agent action response and logs. Build failures return internal server error from the agent and keep the service stopped. Runtime exits appear in /v1/services as last_exit_status and in the log buffer as process-exit lines.
Allocation failures should be debugged from the control-plane side. A 503 from game allocation means no healthy registered game instance currently satisfies realm, zone, endpoint, draining, pressure, and capacity checks.
Local And LAN Workflows
Local defaults are:
- Login:
127.0.0.1:7000 - Game:
127.0.0.1:7100 - Control-plane:
127.0.0.1:7200 - Local agent:
127.0.0.1:7300
Local HTTP is allowed by default for control-plane clients. The shared development control secret is acceptable only for local development.
For LAN workflows:
- Set a non-default
AETHER_CONTROL_AUTH_SECRETon control-plane, login, game, and panel environments. - Use HTTPS for control-plane traffic, or set
AETHER_CONTROL_ALLOW_INSECURE_HTTP=trueonly for trusted development LANs. - Start a control-agent on each host with
AETHER_AGENT_WORKSPACE_ROOTandAETHER_AGENT_TOKEN. - Add each agent base URL and token to the panel config.
- Open only the required service, realtime, QUIC, control-plane, and agent ports.
- Keep host clocks in sync so signed request timestamps stay inside the 300 second skew window.
When a LAN panel cannot see a service, check in this order: panel config URL, firewall, agent token, service /health, service /ready, control-plane signed reads, and then allocator state.