ContainerCost
What one container cost the worker that leases it, split into the three components of CostComponent.
Nebula · Packages/com.1by3.nebula/Runtime/Orchestrator/ContainerCost.cspublic struct ContainerCostWhat 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();