Skip to content

feat: support staged, spike, and arrival-rate load profiles - #46

Merged
ragilhadi merged 1 commit into
masterfrom
claude/flux-issue-33-ulzkh9
Aug 17, 2026
Merged

feat: support staged, spike, and arrival-rate load profiles#46
ragilhadi merged 1 commit into
masterfrom
claude/flux-issue-33-ulzkh9

Conversation

@ragilhadi

Copy link
Copy Markdown
Owner

Summary

Closes #33. Flux previously modeled load only as a fixed concurrency (with an optional ramp_up), which cannot express a stepped load, a hold period, a spike, or a target request-arrival rate. This adds a load_profile configuration section that replaces concurrency/duration/ramp_up when configured:

load_profile:
  type: stages
  stages:
    - duration: 30s
      target_concurrency: 10
    - duration: 2m
      target_concurrency: 100
    - duration: 15s
      target_concurrency: 300   # spike
    - duration: 30s
      target_concurrency: 0     # ramp down
load_profile:
  type: arrival_rate
  target_rps: 200
  duration: 5m
  max_concurrency: 500

Existing configs with no load_profile are completely unaffected — same fields, same execution path, same behavior.

Implementation

  • config: a validated LoadProfile enum (stages / arrival_rate), mutually exclusive with ramp_up since a profile fully replaces the warm-up model. Stage/arrival-rate durations support ${VAR} expansion like every other duration field. --concurrency/--duration CLI overrides are rejected when load_profile is set, so timing always comes from one place.
  • executor — staged scheduler: every worker any stage could need is spawned up front; a worker outside the currently active stage's target_concurrency idles (50ms poll) instead of sending requests. This makes transitions land on schedule with no worker-startup latency mid-run, while reusing the same worker-loop code path as fixed concurrency, so retries, think time, scenarios, and cancellation behave identically.
  • executor — arrival-rate pacer: request starts are paced with a tokio::time::interval, independent of how long each request takes. In-flight requests are bounded by a Semaphore sized to max_concurrency; a pacing tick that finds no free permit is counted as saturated and skipped rather than queued, so an overloaded target shows up as a number instead of unbounded task creation.
  • metrics/reporter: a per-stage breakdown (label, configured target, planned duration, and the usual request/latency/error metrics observed while active) and a configured-vs-achieved-rate summary are attributed as requests complete, and surfaced in the terminal summary, JSON report, and HTML report. A plain fixed-concurrency run carries no load_profile and an empty stages list.

Testing

  • cargo test — 138 tests pass, including new coverage for profile validation (empty/zero-duration stages, non-positive target_rps, zero max_concurrency, the ramp_up/load_profile conflict, env-var expansion), stage transition timing, arrival-rate pacing and saturation tracking, and cancellation mid-stage / mid-pacing.
  • cargo clippy --all-targets and cargo fmt --check — clean.
  • Manual smoke test against a local server (both debug and --release builds) confirmed staged concurrency transitions on schedule, arrival-rate pacing tracks the target rate (97/100 req/s achieved in a release build against a fast local target), and per-stage request counts sum exactly to the run total.
  • README updated with stage/spike/arrival-rate examples and a new "Load Profiles" section; two new samples/*.yaml configs added.

Version

Bumped vars/version and Cargo.toml from v1.6.0 to v1.7.0 (minor), per this repo's existing release convention.

Test plan

  • cargo test
  • cargo clippy --all-targets
  • cargo fmt --check
  • Manual run against a local HTTP server with a staged config
  • Manual run against a local HTTP server with an arrival-rate config (debug and release builds)

Generated by Claude Code

…elease v1.7.0

Flux previously only modeled load as a fixed concurrency plus optional
ramp_up, so it could not express a stepped load, a hold period, a spike,
or a target request-arrival rate. This adds a `load_profile` configuration
that replaces `concurrency`/`ramp_up` when set:

- config: a `LoadProfile` enum with `stages` (a sequence of
  duration/target_concurrency steps) and `arrival_rate`
  (target_rps/duration/max_concurrency) variants, validated and
  environment-variable-expandable like the rest of the config;
- executor: a staged scheduler spawns every worker any stage could need up
  front and gates each on the currently active stage's target
  concurrency, so transitions happen on schedule without respawning
  tasks; an arrival-rate pacer paces request starts with a tokio interval
  and bounds in-flight requests with a semaphore, counting a pacing tick
  that finds no free permit as saturation instead of queuing unbounded
  work;
- metrics/reporter: a per-stage breakdown and configured-vs-achieved rate
  summary are attributed as requests complete and included in the
  terminal summary, JSON report and HTML report; a plain fixed-concurrency
  run carries no load_profile and an empty stages list, so existing
  reports are unaffected;
- cancellation, retries, think time and scenarios reuse the same
  execution paths as fixed concurrency, so they behave identically under
  a load profile.

Also releases v1.7.0 and documents stage/spike/arrival-rate examples in
the README and samples/.

Co-authored-by: Claude <noreply@anthropic.com>
@ragilhadi
ragilhadi merged commit 39b2ef5 into master Aug 17, 2026
9 checks passed
@ragilhadi
ragilhadi deleted the claude/flux-issue-33-ulzkh9 branch August 17, 2026 17:12
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.

feature: support staged, spike, and arrival-rate load profiles

2 participants