The raw numbers are in soak-2026-10-11.json. The
test is apps/bezgelor_world/test/combat/soak_test.exs. All the data is
synthetic: in-process headless players, no real users.
Scenario
| Parameter | Value |
|---|---|
| Duration | 300 s |
| Players | 50 (all six classes, level 15) |
| Creatures | 500 hostile, levels 11-15, interrupt armor 0 (60%), 1 or 2 (20% each) |
| Area | 300 × 300 m, one zone instance |
| Player behaviour | Every 1.2-1.8 s: top up resources, cast a random level 1-15 kit ability at a creature within 25 m (else a random one); move 5 m in a random direction 25% of the time; wake up when dead |
| Creature behaviour | Server AI: aggro, chase, swing, leash and evade, die and respawn |
| Viewers | Each player views the creatures within 120 m, so movement and combat packets are encoded and sent |
| Zone tick | 250 ms (creature AI, auras, regeneration, scripts, loot) |
| Client oracle | Off, to keep the shared host's load down. The zone scenario tests and the e2e tests oracle-check every packet. |
Results (run of 2026-10-11)
| Metric | Value |
|---|---|
| Zone ticks | 1,194 (about 4 per second, on schedule) |
| Tick p50 / p95 / p99 / max | 6.4 / 19.9 / 22.7 / 106.9 ms |
| Tick budget | 250 ms; the asserted p95 limit is 100 ms |
| Zone mailbox, max | 59 messages |
| Zone process heap | 7.3 MB at the first 10 s sample, 9.1 MB at the last (it moves between 4.5 and 9.3 MB with GC) |
| VM processes | 237 before, 289 at peak, 287 after the players left and the zone stopped (the 50 fake connections live until the test ends) |
| Player casts | 7,536 (25.1 per second) |
| Player wake-ups | 1,480 (the creatures fight back) |
| Creatures in combat at the end | 112 |
| Consistency checks | 30 (one every 10 s) plus a final check; all passed |
| Crashes | none |
Each consistency check verifies that:
- no unit has negative health, or more than its maximum;
- dead creatures hold no auras, threat or target;
- creatures in combat have a threat list of known units;
- idle creatures have no threat;
- no player is flagged in combat while on no threat list;
- no expired aura lingers;
- dead players have a ghost and no pending cast.
Earlier runs the same day
| Run | Ticks | p50 | p95 | p99 | max | Mailbox max | Heap first → last |
|---|---|---|---|---|---|---|---|
| 60 s, unconstrained, machine busy | 240 | 8.6 ms | 27.4 ms | 37.6 ms | 95 ms | 61 | 7.3 → 9.1 MB |
| 300 s, unconstrained, machine at load 50-100 | 1,187 | 7.4 ms | 21.9 ms | 35.0 ms | 116 ms | 64 | 7.3 → 7.4 MB |
300 s, under scripts/limited.sh |
1,190 | 6.9 ms | 19.8 ms | 22.6 ms | 109 ms | 66 | 7.3 → 9.1 MB |
The first 300-second run found a crash, since fixed. A dead player whose ghost couldn't be built (its database lookup failed) took the zone process down on leaving.
Machine
- 20 cores and 31 GB RAM: a shared developer host, with other sessions' test suites running at the same time.
-
The run was limited by
scripts/limited.sh:- a systemd user scope with MemoryMax 6 GB, swap capped at 1 GB and CPUQuota 400%;
-
nice 10,ioniceidle; -
Erlang
+S 4:4 +SDcpu 2:2 +SDio 2; - the machine-wide heavy-job lock.
- Software: Erlang/OTP 28, Elixir 1.19.6, PostgreSQL 16 (the zone writes durability on death through the Ecto sandbox).
Reproduce
From a checkout with dependencies fetched and PostgreSQL running (see the repository's testing notes):
cd apps/bezgelor_world
SOAK_SECONDS=300 \
SOAK_REPORT=$PWD/../../docs/community/test-reports/soak-$(date +%F).json \
LIMIT_HEAVY=1 LIMIT_TIMEOUT=30m \
../../scripts/limited.sh mix test test/combat/soak_test.exs --include soak
SOAK_TICK_P95_MS changes the asserted p95 limit (default 100). Without
scripts/limited.sh, run plain mix test ...; the numbers will reflect your
machine.
What it does not cover
- Idle AI across a whole continent. Issue #93: Alizar's tick p95 is about 400 ms with one player, because every creature on the continent runs idle AI. This soak uses one 300 m area.
- Network I/O. The connections are in-process fake sockets: packets are encoded but not sent over TCP.
- Database writes, beyond durability on death.
See also the combat audit summary.