Load-tester for rippled/clio pathfinding, with a Vue 3 dashboard for multi-round runs and fall-off comparison. Supports burst (all at once) and ramp (up → hold → down).
| Mode | Command | What it does |
|---|---|---|
| UI (dev) | npm run dev |
Express API + Vite Vue app at http://localhost:5173 |
| UI (prod) | npm run build && npm start |
Serves built web/dist |
| CLI | npm run cli -- --skipDiscover --max=50 --observeMin=2 |
Terminal load test |
| Discover | npm run discover -- [N] |
Cache wallets with ≥N funded trustlines (default N=200) |
Default node: ws://192.168.12.238:6006
- Open all path_finds in parallel (as fast as possible)
- Ready — wait until sessions emit async updates
- Observe — hold and graph metrics for N seconds
- Close all at once
- Ramp up — open +1 path_find every interval (default 3s) until max concurrent
- Ready — wait until sessions emit async updates
- Hold / observe — keep all open at the cap for the observe window
- Ramp down — close −1 path_find every same interval until none remain
You need to cache the wallets used first via npm run discover that is written into data/wallets.json which you can manually edit as well (just reload it afterwards).
Once that is done npm run dev and point your browser to http://localhost:5173
npm install
npm run discover # once, if data/wallets.json is missing (default ≥200 trustlines)
# npm run discover -- 50 # optional: lower threshold
npm run dev- Defaults: Ramp, 1s interval, max 50, hold 30s
- Pick open mode: Burst or Ramp
- Ramp: set interval (used for both ramp-up and ramp-down)
- Pick max concurrent path_finds (the cap)
- Set observe window (hold time at cap in ramp mode)
- Fire test round — live charts stream over SSE
- Multi-select history rows → Compare charts
- Rerun on a history row — repeats the same
path_findcreates (source, dest, amounts) in the same order for an apples-to-apples re-test
Only one run at a time.
npm run cli -- --skipDiscover --max=200 --observeMin=2
npm run cli -- --skipDiscover --max=10 --observeSec=30 --inspect
npm run cli -- --skipDiscover --mode=ramp --addIntervalSec=3 --max=50 --observeSec=60
npm run cli -- --replay=data/results/loadtest-….json --observeSec=60| Flag | Default | Meaning |
|---|---|---|
--endpoint |
ws://192.168.12.238:6006 |
WebSocket URL |
--max / --cutoff |
50 |
Max concurrent path_finds (cap) |
--mode |
ramp |
burst or ramp (up → hold → down) |
--addIntervalSec |
1 |
Ramp: seconds between +1 up and −1 down |
--observeMin |
Hold-at-cap / observe window (minutes) | |
--observeSec |
30 |
Observe / hold-at-cap window (seconds) |
--readyTimeoutSec |
120 |
Max wait for all sessions to update |
--skipDiscover |
Use data/wallets.json |
|
--replay=PATH |
Rerun a prior results JSON with the same path_find sequence | |
--inspect |
Interactive session drill-down after CLI run |
Every completed run records an ordered request plan (requestPlan): each session’s source, destination, destination_amount, and send_max (including token-retry candidates).
- UI: click Rerun on a history row →
POST /api/runs/:id/rerun - CLI:
--replay=path/to/loadtest-….json(full results file preferred; works from sessions if plan is missing) - Timing knobs (
mode, interval, observe window, endpoint) can still be overridden; only the path_find payloads and their order are fixed.
Per the path_find docs, only one path_find may be open per WebSocket. This tool opens one XrplClient per concurrent request.
server/ # Express API + Vite middleware
web/ # Vue 3 UI (Chart.js)
src/ # Load-test engine (shared CLI + API)
data/wallets.json # Wallet cache
data/results/ # Run outputs + UI index
Every run opens a dedicated WebSocket that polls:
| RPC | Role |
|---|---|
server_info |
server_state (FULL / SYNCING / CONNECTED / TRACKING / PROPOSING), ledger seq/age, load_factor, last_close converge time & proposers, state_accounting |
get_counts |
Admin object/memory counters — especially pathfind types (xrpl::PathRequest, PathFindTrustLine, STPath, STPathElement, STPathSet) plus Transaction/NodeObject/write_load. Skipped cleanly if the endpoint is not admin |
The report includes:
- Verdict: consensus OK (stayed FULL/PROPOSING) vs degraded (saw SYNCING/CONNECTED/etc.)
- State changes with timestamps and phase
- Time-series for charts (state rank, load_factor)
- Ledger advance and state_accounting transition deltas over the run
CLI final report prints a ── consensus / server health ── section; the Vue UI shows live server_state stats and charts, plus a Consensus column in history.
- Max concurrency is capped at 1000 in the API/UI.
- Loads above ~200 sockets can hit OS fd limits or node capacity — the form warns above 200.
- Path quality under load is not guaranteed; empty
alternativesis a useful stress signal. get_countsrequires admin access on the rippled port; without it, consensus verdict still works fromserver_infoalone.