Skip to content

Limit inbound events and absorb shared broadcast bursts - #537

Merged
linkdata merged 1 commit into
mainfrom
fix/inbound-event-rate
Oct 7, 2026
Merged

linkdata merged 1 commit into
mainfrom
fix/inbound-event-rate

Conversation

@linkdata

@linkdata linkdata commented Oct 7, 2026

Copy link
Copy Markdown
Owner

Incoming events can drive shared-tag broadcasts fast enough to disconnect other users, especially pages with only one element. Pace inbound events per Request and give small pages enough queue space to absorb synchronized bursts.

  • Add Jaws.MaxEventRate: 100 records/s by default, zero selects the default, negative disables it. Click, ContextMenu, Input, and JsVar share the budget, including records batched in one frame. Events wait in order; Remove consumes no budget. Use github.com/linkdata/rate.
  • Raise the subscription queue floor to 64 while retaining element-count scaling.
  • Add the rate argument directly to wire.ReadLoop. Check cancellation after an enabled limiter wait; preserve shutdown and idle-ping behavior.
  • Document pacing, bound JavaScript reads, and shared-broadcast bandwidth requirements. The initial event waits 10 ms at the default rate. High-rate browser activity can accumulate delay.

No per-IP aggregate budget is added. Per-Request pacing and burst headroom do not prevent overload when aggregate broadcasts exceed a recipient's sustained capacity; applications should use Dirty/Update coalescing or keep broadcasts within their clients' bandwidth.

Validation: focused transport/request tests, full go test -race ./... and production tests with JAWS_REQUIRE_NODE=1, go generate, gofmt, go vet, staticcheck, golangci-lint, gosec, and go build pass. Reviewed the affected rendered Go docs separately. Tests cover batching, ordering, defaults, disabled/custom rates, idle recovery, cancellation, ping timing, and a continuously reading victim under real WebSocket traffic.

The committed BenchmarkWSBroadcastBurst uses 16 synchronized senders, real WebSockets, and an unthrottled one-element recipient. Server-side pacing is disabled to isolate queue capacity. Linux/arm64; six samples per rate/CPU combination:

go test -run '^$' -bench '^BenchmarkWSBroadcastBurst$' -benchtime=400ms -cpu=1,4 -count=6 -benchmem .
benchstat cap-8.txt cap-64.txt
Events/s per sender CPUs Disconnects, cap 8 → 64 Median delivered, cap 8 → 64
25 1 0/6 → 0/6 100% → 100%
25 4 4/6 → 0/6 70.05% → 100%
400 1 2/6 → 0/6 100% → 100%
400 4 6/6 → 0/6 10.83% → 100%

Total recipient disconnects fell from 12/24 to 0/24. Benchstat reports the 400/s, 4-CPU delivery improvement at p=0.002. An exploratory 16/32/64-capacity sweep also passed at 32; 64 provides additional burst headroom. These short runs measure burst tolerance, not a guarantee against sustained overload. Time/op includes client pacing; allocations include more completed delivery work when the recipient stays connected.

Fixes #536.

@linkdata
linkdata merged commit d46cc07 into main Oct 7, 2026
7 checks passed
@linkdata
linkdata deleted the fix/inbound-event-rate branch October 7, 2026 07:07
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.

Per-event broadcasts on shared tags let one peer disconnect other users (ErrRequestOverloaded)

1 participant