Skip to content

fix(sim): least-loaded pick ignores load on self-pooled kinds - #100

Open
palash247 wants to merge 1 commit into
workersio:mainfrom
palash247:fix/lb-least-loaded-pooled-kinds
Open

palash247 wants to merge 1 commit into
workersio:mainfrom
palash247:fix/lb-least-loaded-pooled-kinds

Conversation

@palash247

Copy link
Copy Markdown

Bug

An equal-weight load balancer in front of database nodes sends every request to the first one.

pickWeightedOrLeastLoaded measures target.busy + waiting. Kinds that run their own slot pool and time work through serveWithin() (db, searchindex, timeseriesdb, graphdb, vectordb, replica, shard, coldstorage) keep busy and the engine queue at 0, so they always look idle and the index tie-break picks the first edge every time.

Repro

client 300 rps → lb → three db nodes (capacity 4, serviceMs 20, so 200 rps ceiling each). After 10 s: arrival rates [~300, 0, 0]; the first db queues and sheds while the other two sit idle. Same for the other seven kinds. Three service nodes split the load as expected.

Fix

  • New optional ComponentBehaviour.load(ctx, state): (in service + waiting) / slots. Pure read, no RNG.
  • The picker uses it when present, else the existing formula, so no other kind changes.
  • Implemented for the shared costed pool (5 kinds), replica, shard and coldstorage.

Test

src/sim/lbPooled.test.ts: the repro above for service and each affected kind (every node must get > 50 rps), plus a determinism check.

  • Without the engine change: 8 failed, 2 passed.
  • With it: 10 passed. Full suite (vitest run): 58 files, 1259 tests pass. tsc -b clean, oxlint no new warnings.

Not verified: run with npm + npx vitest run, not bun.

pickWeightedOrLeastLoaded measured state.busy plus the engine waiting
list. Kinds that run their own slot pool and time work with
serveWithin() (db, searchindex, timeseriesdb, graphdb, vectordb,
replica, shard, coldstorage) leave both at 0, so every one of them
looked idle and an equal-weight load balancer in front of them sent
all traffic to the first.

Add an optional load() behaviour hook, (in service + waiting) / slots,
implemented by those kinds; the picker uses it when present and keeps
the old formula otherwise. Pure read, no RNG, so determinism holds.
@palash247
palash247 requested a review from xevrion as a code owner October 28, 2026 12:30
@vercel

vercel Bot commented Oct 28, 2026

Copy link
Copy Markdown

@palash247 is attempting to deploy a commit to the breakscale OSS Program Team on Vercel.

A member of the Team first needs to authorize it.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant