ACTIAS

Where load goes

What each surface costs at scale, and which part of the cluster absorbs it.

Per surface

SurfaceScales withSerializes at
HTTP requestworker count, statelessnothing
Object callinstance countthe instance's home task
Object first touchone placement-store claimthe placement store; the holder cache absorbs repeats
Database read, read_oneworker count, via replicasnothing
Directory queryclass count; one reader per classthe class's reader node
Publishnodes holding followers, plus one per object followerthe publisher's pump
KVthe kv store (Postgres, or ScyllaDB at volume)nothing
Queue messagequeue countthe queue's home task, 16 messages per firing

The unit of serialization

The object instance. One task runs its calls one at a time, which is what makes its transactions and its event log trivial; the price is that one instance is bounded by one core and one file.

A hot instance is therefore a modelling problem, not a tuning problem. Split hot state across instances: a Channel per room rather than one router object, a counter per shard rather than one global counter.

What one node absorbs

  • Followers: delivery cost is per node for sockets, so co-located sockets are nearly free. See event delivery.
  • Database reads: read and read_one answer from a replica without touching the home. Every object method reaches the home. See placement.
  • Scripts: pointer and blob caches keep the steady state node-local. See the cluster.
  • Misrouted object calls: the holder cache forwards them from memory; the placement store is consulted on first touch and after a home moves, not per call.

Where each queue is bounded

flowchart LR
    call([call]) --> mb[object mailbox<br/>128 deep: the caller waits]
    mb --> gate[ack gate<br/>10 s: then the answer is unknown]
    gate --> ship[ship flights<br/>32 at once, 8 reserved for gated writes]
    ev([publish]) --> inbox[connection inbox<br/>256: refuse and sever the edges]
    ev --> edge[object edge<br/>8 attempts: drop the edge]
    msg([send]) --> q[queue message<br/>5 attempts: dead-letter]
BoundAtBehaviour
object mailbox128 callsbackpressure: the caller waits, nothing is dropped
ack gate10 s (OBJECT_ACK_GATE_MS) for a replica quorum or the storea written call answers "outcome unknown"; the write keeps trying to ship
ship concurrency32 flights, 8 reserved (OBJECT_SHIP_CONCURRENCY, OBJECT_SHIP_RESERVED)flights a caller is waiting on always find a slot
connection inbox256 itemsdeliveries: refused and the edges severed; client frames: the wire closes
object edge8 attempts, 500 ms doublingthe edge is dropped
queue message5 attempts, 2 s doubling to 1 hdead-lettered

The platform sheds at the edges and blocks in the middle: the one bound that waits rather than drops is the mailbox, because a call has a caller to answer.