Nebula

Replace gateways and workers

Check protocol and content compatibility, drain server processes, and verify client traffic after replacement.

Check compatibility before replacing server processes in a running game. The drain procedures below apply to builds that use the same wire protocol and compatible game content.

A mesh is the group of processes running one game world. Its gateway accepts client connections, and its workers simulate entities in assigned containers, or areas of the world. The orchestrator manages worker processes and assignments through the control plane.

Check compatibility

ConnectionCurrent requirement
Native or browser client to gatewayProtocols 23 and 24: HelloMsg.MinProtocolVersion is 23 and HelloMsg.ProtocolVersion is 24.
Gateway to worker, worker to workerExact protocol match.

The gateway records the client's accepted protocol version and returns it in Welcome.negotiated_version. A client outside the supported range receives ProtocolUnsupported.

Protocol changes need a separate rollout plan

A gateway of this version accepts clients of protocols 23 and 24. Protocol 24 added relevance tiers and changed nothing a client reads, so clients built with protocol 23 keep working with it. Gateways and workers of a mesh must still run the same protocol. Protocol 22 added forwarded token claims, between gateways and workers. Protocol 23 added deliberate session endings (a client's goodbye with NebulaClient.Leave, a server's kick, a notice that the server is shutting down), a recovering join hold and the owner-connected flag. Before 1.0 a protocol change may close the window to the new version, and protocol 23 did: a gateway of this version refuses clients built with protocol 22 or older, which includes clients of the 0.1.0-beta.0 release. Rebuild and ship those clients together with the servers. Replacing a gateway with one that uses a different protocol also prevents it from communicating with existing workers. These drain procedures do not provide a rolling upgrade across incompatible server protocols; plan a coordinated restart or a separate compatible mesh.

Configure game content compatibility

Nebula's protocol does not describe your scenes, prefab identifiers, component layouts, or custom serialized data. Keep those compatible across processes, and declare your game's content version with GameContentVersion on NebulaConfig.

  • A gateway configured with GameContentVersion = 0 disables this check.
  • With a nonzero version, the default requires an exact client match.
  • Set MinGameContentVersion to a nonzero value no greater than GameContentVersion to admit that inclusive range.

The gateway compares the client's number with its configured range. Your game determines which content versions can interoperate. Nebula does not migrate content.

The command-line options -nebula-content-version <n> and -nebula-min-content-version <n> override these values on the process receiving them. Replace <n> with your chosen version number and configure each gateway that accepts clients. See Configuration.

Prepare the replacement

  1. Build and stage server processes with matching wire protocols and compatible game data.
  2. Ensure the remaining workers have enough capacity to accept transferred entities.
  3. Configure the client-facing address to reach another healthy gateway during replacement. Nebula does not provide a load balancer.
  4. Keep the gateway signing key, mesh token, and encryption certificate consistent across the fleet. See Authentication and Encrypt client connections.

Drain and replace a gateway

Draining stops new joins and asks connected clients to reconnect. Clients present their session tokens to reclaim their identities and player-controlled entities, or pawns. Reclaim must finish within SessionReclaimSeconds to retain a disconnected session's pawn.

  1. Set IControlPlane.SetGatewayDraining(gatewayId, true) through your server tooling, or use the dashboard's gateway drain action. See the control-plane API.
  2. Wait for clients to reconnect through a healthy gateway. GatewayDrainReconnectSeconds sets the reconnect deadline, defaulting to 10 seconds.
  3. Confirm the draining gateway has no active clients before stopping it. If the deadline expires first, investigate clients that have not reconnected.
  4. Start the replacement, confirm it accepts clients, and check that reclaimed clients retain their sessions and pawns.
  5. Repeat for the next gateway.

Clear the draining flag to cancel a drain. A client always retries its configured address, so an address that reaches only the stopped gateway prevents successful reclaim.

A gateway that is stopped without a drain still tells its clients before it exits. On SIGTERM or Ctrl-C (the standalone gateway), or when its Unity object is destroyed or the application quits, it sends every client the drain notice, or, when no other gateway is serving, a notice that the server is shutting down. It then waits up to GatewayShutdownDrainSeconds (default 0.5 s) for the notices to go out, less if every client hangs up first. Clients reconnect at once instead of waiting out their transport's disconnect timeout. This does not replace the drain above: a client told at shutdown has only its own reconnect schedule to find another gateway, and the stop does not wait for anyone to reconnect. Set GatewayShutdownDrainSeconds to 0 to stop without telling anyone.

Drain and replace a worker

Authority is responsibility for simulating an entity. A handover transfers that authority and the entity's state to another worker.

Use the orchestrator's worker retirement controls to move assignments and hand over authority before terminating a process. See Autoscale workers for managed worker retirement.

  1. Retire the worker through your deployment or orchestrator controls while other eligible workers have capacity.
  2. Wait until the worker owns no containers and reports zero authoritative entities. An empty assignment list alone does not prove that entity transfers have finished.
  3. Stop the drained process if your worker host has not already stopped or parked it, then start the replacement build.
  4. Confirm the replacement registers and receives assignments. Verify fresh client input and replicated state after the transfer.

WorkerDrainTimeoutSeconds limits how long the orchestrator waits for entities to transfer during retirement. If that deadline expires, it may stop the worker before every transfer finishes. Set the limit for your workload and investigate transfers that exceed it; do not assume a timeout is a successful drain.

Handle a refused join

Read NebulaClient.JoinRejectReason and LastError to display the refusal. ServerProtocolWindow contains the gateway's supported protocol range, and ServerContentVersion contains its configured content version.

For a NebulaClient instance named client, subscribe to JoinRefused in your game's connection code:

client.JoinRefused += rejected =>
{
    if (rejected.Code == JoinRejectReason.ProtocolUnsupported)
    {
        bool clientIsOlder = HelloMsg.ProtocolVersion < rejected.SupportedMinVersion;
        ShowMessage(clientIsOlder
            ? "Update this game before joining."
            : "This server does not support this client build.");
    }
    else if (rejected.Code == JoinRejectReason.ContentVersionMismatch)
    {
        ShowMessage($"This server requires compatible content for version {rejected.ServerContentVersion}.");
    }
};

Import the Nebula namespace. ShowMessage(string message) represents your game's message display method. JoinRefused runs on the main thread; the client stops automatic retries for these compatibility refusals. A draining gateway instead returns a retryable refusal.

On this page