Nebula
Orchestrator

ContainerCost

What one container cost the worker that leases it, split into the three components of CostComponent.

generated from the sources
public struct ContainerCost

What one container cost the worker that leases it, split into the three components of CostComponent. One row per container per worker, refreshed at the telemetry cadence (WorkerTelemetry.IdleIntervalSeconds) and kept by the orchestrator per lease (MeshTelemetry.CopyContainerCost); the dashboard, GET /api/cost and the scaler's "unsplittable container" reason all read the same rows. Design record: docs/cost-telemetry.md.

Absolute numbers, not shares: a share cannot say whether one container alone on a worker is hot because of what it simulates or because of what it sends. Dominant is decided by Resolve, which measures every component against a budget of its own.

Fields

ContainerId

public string ContainerId;

The container these numbers are about.

ScopeKey

public string ScopeKey;

Its scope (EntityLocation.ScopeKey): empty in the public world, the instance key inside an instance.

WorkerId

public string WorkerId;

The worker that reported it.

EntityCostSum

public float EntityCostSum;

The cost-weighted sum of the authoritative entities inside it: for each one, its category weight from CostWeights times its own NebulaCost weight. CostWeights.Base is not included; the orchestrator adds it (a leased container costs something when empty).

TickShareMs

public float TickShareMs;

Milliseconds of NetworkTick per simulated tick spent on this container's entities, measured.

TickShare

public float TickShare;

TickShareMs as a fraction of the simulation time this worker attributed to containers at all. The parts of a tick that belong to no container (physics, interest, publishing) are outside it, so the rows of one worker sum to 1 and not to its utilization.

BytesOutPerSec

public long BytesOutPerSec;

Bytes per second of world state, netvars and sync state sent to gateways for this container's entities, counted once per receiving gateway.

GatewayBytesPerSec

public long GatewayBytesPerSec;

Bytes per second of owner state: the part of the traffic a gateway relays to one client each.

GhostCount

public int GhostCount;

Ghosts of other workers' entities this worker holds for this container.

Dominant

public CostComponent Dominant;

Which component this container is most expensive in (see Resolve).

DominantSaturation

public float DominantSaturation;

How saturated Dominant is, against its budget. 1 = the whole budget.

ReceivedAt

public double ReceivedAt;

When the report arrived, on the telemetry clock.

Properties

DominantName

public string DominantName { get; }

The name Dominant goes by in a reason string, the JSON and the dashboard.

Methods

NameOf

public static string NameOf(CostComponent c);

The lowercase wire name of a component.

ComponentOf

public static CostComponent ComponentOf(string name);

The component a wire name (NameOf) stands for; anything unknown reads as CostComponent.Simulation.

Resolve

public static void Resolve(ref ContainerCost row, float tickPeriodMs, double linkBytesPerSec);

Decide Dominant and DominantSaturation for one row by measuring each component against a budget of its own: simulation against the tick period, replication and the gateway relay against linkBytesPerSec (NebulaConfig.CostLinkBudgetMbps). Comparing the three against each other directly would be comparing milliseconds with bytes, and comparing each container's share of its worker would call the only container on a worker dominant in everything at once - which is exactly the case the scaler needs an answer for. Ties go to simulation, then replication, so the answer is stable between passes. Pure function.

Normalize

public static void Normalize(IList<ContainerCost> rows, float tickPeriodMs, double linkBytesPerSec);

Fill in TickShare for every row of one worker (they are a fraction of that worker's own attributed simulation time) and resolve each row's dominant component. Called once per accepted telemetry document, over that document's rows only.

Write

public static void Write(JsonWriter w, in ContainerCost row, float capacitySaturation = 0f);

One row as the dashboard and GET /api/cost serve it. capacitySaturation is NebulaConfig.CapacitySaturation, so the row can also say whether this container counts as at capacity (docs/capacity-admission.md); 0 leaves atCapacity false.

ToString

public override string ToString();

On this page