Skip to content

Load Generation for Plateau#83

Open
AnIrishDuck wants to merge 14 commits into
mainfrom
claude/magical-clarke-0lgqx5
Open

Load Generation for Plateau#83
AnIrishDuck wants to merge 14 commits into
mainfrom
claude/magical-clarke-0lgqx5

Conversation

@AnIrishDuck

@AnIrishDuck AnIrishDuck commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

This code is very low-quality (e.g. re-implements sampling from a standard distribution instead of using rand) and effectively throw-away. Here for reference only.

claude added 9 commits June 17, 2026 22:27
…vers

Extracts shared worker loop from run() into run_tasks(), adds run_external()
that skips the embedded server, and adds a new `load` binary with CLI flags
for URL, sample file, topics, partitions, rows, write interval, and duration.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GAMUPUAesj4bPh2y2cvaKc
- `load`: continuous streaming load generator targeting an existing server
  (--url, --sample, --topics, --partitions, --rows, --interval-ms, --duration-secs)

- `batch-load`: batch-job simulator with staggered per-partition schedules
  - TOML config with per-topic Arrow sample files (each topic keeps a fixed schema)
  - Deterministic per-batch RNG seed so data is reproducible
  - Evenly staggered fire times across all partitions within each batch period
  - --speed multiplier to compress schedule (e.g. speed=60 runs 1h batches every 1min)
  - JSON state file tracks last completed batch per partition; on restart,
    missed batches are caught up immediately before resuming normal schedule

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GAMUPUAesj4bPh2y2cvaKc
Each topic now carries its own partitions/rows/batch_interval, with an
optional [defaults] table supplying fallbacks. batch_interval is therefore
per-topic, so different topics run on independent (sped-up) schedules and
each topic's partitions are staggered across that topic's own period.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GAMUPUAesj4bPh2y2cvaKc
…ation

Replaces the hand-listed [[topics]] config with a generative approach:

- [topics] count/active/rotation_interval configure a pool of N topics,
  with `active` topics writing at any given time
- columns_min/columns_max define the random column count range per topic
- Schemas are generated once (via sample_flat + FromDataType), written as
  Arrow IPC files to schemas_dir, and reloaded on restart — no data loss
- A stable schemas_seed in state.json enables regeneration if files are lost
- The active window slides forward by `active` every rotation_interval/speed;
  on restart, the window is recomputed from elapsed time so the sim stays
  consistent with the wall clock
- Each topic's partitions are staggered across that topic's batch period
- Catchup: missed batches fire immediately on restart before resuming schedule

Example config:
  speed = 60.0
  [topics]
  count = 200
  active = 8
  rotation_interval = "1h"
  columns_min = 3
  columns_max = 35
  batch_interval = "1h"
  partitions = 4
  rows = 10000

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GAMUPUAesj4bPh2y2cvaKc
…mpling

- partitions_min/max: each topic draws its own partition count
- columns_min/max: now sampled from a normal distribution (was uniform)
- rows_min/max define an overall rows-per-insert distribution; each topic
  draws two values from it to form its own [min, max] sub-range, and every
  insert samples a row count from that per-topic range
- All range draws use a clamped normal distribution (Box-Muller, mean at
  midpoint, sigma = range/4) via a shared normal_range helper
- Per-topic parameters are derived deterministically from
  hash(schemas_seed, topic_idx), so they are stable and recomputable across
  restarts without a manifest; schema files are independently regenerable
- Add unit tests: range bounds, param determinism, schema load-back + no
  spurious regeneration

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GAMUPUAesj4bPh2y2cvaKc
Dockerfile:
- Combined cargo build now builds both plateau and batch-load binaries
- Named the existing final stage `plateau`
- Added `batch-load` stage copying the bench binary

CI (rust.yml):
- Added BENCH_REGISTRY_IMAGE env var (ghcr.io/wallaroolabs/plateau-bench)
- Added --target plateau to existing build jobs
- Added build-bench-amd64, build-bench-arm64, merge-bench jobs mirroring
  the plateau pattern
- Bench jobs run on push to main, version tags, workflow_dispatch, and PRs
  (guarded by same-repo check so fork PRs don't fail on missing secrets)
- merge-bench tags with sha, branch, pr number, and semver

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GAMUPUAesj4bPh2y2cvaKc
bench-image.yml is workflow_dispatch-only so it never runs on PRs or
routine pushes. Trigger it from the Actions tab (or gh workflow run
bench-image.yml --ref <branch>) whenever a new bench image is needed.

rust.yml is cleaned up: BENCH_REGISTRY_IMAGE env var and the bench build
jobs are removed; the plateau build jobs retain --target plateau.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GAMUPUAesj4bPh2y2cvaKc
No arm build needed. Drops the digest/artifact/merge pattern in favour of
a single build-and-push job that pushes tags directly.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GAMUPUAesj4bPh2y2cvaKc
append_records sends the full batch in one request, which can exceed the
server's DefaultBodyLimit when rows_max is large. append_queue auto-splits
at the client's DEFAULT_MAX_BATCH_BYTES (100KB), so large batches are
chunked before they hit Axum's body limit.

Co-Authored-By: Claude <[email protected]>
claude and others added 5 commits June 25, 2026 19:46
… on failure

Axum 0.6's DefaultBodyLimit returns 400 (not 413) when the limit is exceeded,
so append_queue's auto-shrink never fires. Fix by:
- Adding Client::with_max_batch_bytes() to allow callers to set a conservative
  limit below the server's 10MB wall
- Setting 8MB in run_batch so append_queue splits proactively before sending
- Logging the row count on batch failure for easier diagnosis

Co-Authored-By: Claude <[email protected]>
Running batch-load through kubectl port-forward causes spurious 400
"Failed to buffer the request body" errors — the apiserver-proxied tunnel
truncates request bodies under sustained load. Running in-cluster talks
straight to the Service and avoids this.

Adds bench/k8s/ with:
- job.yaml: ConfigMap + PVC + Job (resumable via persisted state/schemas)
- batch-config.toml: sample config
- README.md: buildx build/push commands (no CI needed) and deploy steps

Co-Authored-By: Claude <[email protected]>
batch-load lives in the bench package, not plateau. Build both with
-p plateau -p bench so both binaries are available to copy.

Co-Authored-By: Claude <[email protected]>
plateau-bench is private like the other org packages, so the Job needs the
same ghcr.io pull secret the plateau pods use. Reference it via
imagePullSecrets (placeholder name to be set per-cluster).

Co-Authored-By: Claude <[email protected]>
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.

3 participants