Skip to content

perf: jittered backoff between CAS retries#117

Merged
joaomdsg merged 3 commits into
mainfrom
feat/cas-backoff
Jun 10, 2026
Merged

perf: jittered backoff between CAS retries#117
joaomdsg merged 3 commits into
mainfrom
feat/cas-backoff

Conversation

@joaomdsg

Copy link
Copy Markdown
Member

Critic panel finding #11 (minor; perf). StateApp.Update/StateSess.Update retried a CAS conflict immediately — a contended key spun through all 100 attempts burning CPU.

Change

Exponential backoff ceiling (100µs doubling, capped 10ms) with full jitter in [0, ceiling) so concurrent retriers de-correlate. Cap stays under a frame (no perceptible latency); first-try success never sleeps. The ceiling clamp also absorbs the int64 overflow a large shift would wrap negative.

Tests

  • ceiling grows, is monotonic, clamps to cap, never overflows negative
  • negative attempt floors to base (no panic)
  • a single sleep stays bounded by the cap

Full ci-check.sh green.

joaomdsg added 3 commits June 10, 2026 19:13
A client value that overflowed a Signal[T]'s narrower numeric type (e.g. 9999
into Signal[int8]) was silently truncated, and a shape mismatch was silently
dropped — the typed Signal was only as safe as a best-effort decode.

Add WithStrictDecode(): a client value that overflows the target int/uint/float
width or whose JSON shape doesn't match the field surfaces an action error and
the handler does not run, so corrupt input can't reach server state. Off by
default (best-effort decode preserved). The decode is factored into
decodeScalarChecked, which reports the error; decodeScalarInto wraps it and
discards it so server-side store decodes keep the lenient contract. The
struct-tag init path stays best-effort (author input, not untrusted client).
StateApp.Update and StateSess.Update retried a CAS conflict immediately, so a
contended key spun through all 100 attempts burning CPU with no pause. Add an
exponential backoff ceiling (100µs doubling, capped at 10ms) with full jitter
in [0, ceiling) so concurrent retriers de-correlate instead of colliding in
lockstep. The cap stays well under a frame so a contended Update adds no
perceptible action latency; the no-contention path (first-try success) never
sleeps.
@joaomdsg
joaomdsg merged commit 67de6e9 into main Jun 10, 2026
4 checks passed
@joaomdsg
joaomdsg deleted the feat/cas-backoff branch June 10, 2026 19:25
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