Releases: Perfscale/perfscale
Release list
v0.7.0
- gRPC load testing: new
std/grpc@v1action family —grpc(one-shot
unary),grpc-connect/grpc-call, andgrpc-stream-open/-send/
-recv/-closefor client/bidi/server streaming. Calls are dynamic (no
codegen): the schema comes from a base64descriptor_set(e.g. fetched over
HTTP and passed through${{ fetch.body_base64 }}) or server reflection
(reflection: true, cached per URL). Payloads are protobuf-JSON with
${…}token expansion,expect_statusasserts the gRPC status code, and
the family reportsgrpc_req_duration,grpc_msg_rtt,grpc_msgs_sent/
grpc_msgs_received, andgrpc_req_failedmetrics. std/http@v1binary responses now returnbody_base64(with an empty
body) when the content type is not textual — previously the body was
lossy-decoded as UTF-8. Textual responses are unchanged.
Full Changelog: v0.6.0...v0.7.0
v0.6.0
Added
-
WebSocket support — six new built-in actions, free and open source like
everystd/*transport. Two styles:A one-shot session (
std/ws@v1) connects, exchanges messages, and
closes in one step — timed as a single latency sample:steps: - uses: std/ws@v1 with: url: wss://stream.example.com/feed messages: - send: '{"op":"subscribe","channel":"trades","id":"sub-${seq}"}' until_json: { type: trade } check: message_matches: { type: trade }
A live connection (
std/ws-connect@v1+ws-send/ws-recv/
ws-ping/ws-close) stays open across steps within an iteration, so WS
traffic interleaves with HTTP steps:steps: - uses: std/ws-connect@v1 with: { url: "wss://stream.example.com/feed" } outputs: feed - uses: std/ws-send@v1 with: id: "${{ feed.id }}" send: '{"op":"order","id":"ord-${seq}","px":${randf(1.05,1.15,5)}}' repeat: 100 interval_ms: 50 - uses: std/ws-recv@v1 with: { id: "${{ feed.id }}", until_json: { type: fill } } - uses: std/ws-close@v1 with: { id: "${{ feed.id }}" }
Text and binary (base64) frames, subprotocols (
graphql-ws, STOMP, …),
wss://withskipTLSVerifyfor staging, and connection profiles via
connection: ${{ config.x }}. Seeexamples/websocket.test.yamland
docs/core/actions.md. -
Dynamic message generator in the open engine: text payloads expand
single-brace tokens per send —${seq},${uuid},${now}/${now_ms}/
${now_iso},${rand(a,b)},${randf(a,b,dp)},${choice(x|y|z)}— and
repeat+interval_msemit a stream of unique messages from one template. -
Message asserts in
std/check@v1:message_contains,
message_matches(JSON-subset), andmessages_count_gtework over the
messageslist any protocol action exposes (WebSocket and FIX alike), with
at-least-one-matches semantics;on: got.messages.0addresses a single
message by position. -
Custom histogram metrics: an action reporting an array of millisecond
samples under itsmetricskey gets a full percentile summary line
(avg/p(50)/p(90)/p(95)/p(99)/min/max count=N). The engine uses it for
ws_msg_rtt— time from a send to the first reply matching your
until-condition. Handshakes and one-shot sessions feedhttp_req_duration;
waiting on server pushes deliberately does not.
Full Changelog: v0.5.0...v0.6.0
v0.5.0
Added
- npm install:
npm install -g @perfscale/exeinstalls the standalone
binary for your platform (esbuild-style optionalDependencies — npm fetches
only the matching@perfscale/<os>-<arch>package; Linux builds are static
musl and run on any distro). Published automatically from every release tag. - Actions can emit custom run metrics: a
metricsobject in a step's output
value (name → number) is summed across VUs/iterations by the native engine and
reported in the summary as<name>: <total> <rate>/s— the same line shape the
downstream parsers already read. Enables protocol-specific dashboards (e.g. FIX
send/receive message rates) without changing the metrics pipeline.
What's Changed
New Contributors
Full Changelog: v0.4.0...v0.5.0
v0.4.0
Added
- New
std/tcp@v1andstd/udp@v1actions: raw TCP/UDP probes — connect (TCP),
send an optional payload (send/send_base64), optionally read a response
and assert a substring (expect), all with per-request timing. Latency feeds
the same metrics as HTTP, so percentiles are comparable across transports. - Config files gain a
before:block: setup steps that run once before the
load (not per iteration). Each step'soutputsis exposed to test steps under
theconfignamespace —${{ config.<name>.<field> }}— for building a
reusable value (e.g. a token or connection profile). A failing setup step
aborts the run before any VU starts. - Config files gain a
variables:block: static values exposed to steps as
${{ vars.<key> }}. - Steps accept
uses:as an alias foruse:. - New
std/file-read@v1action: read a file once into a process-wide cache
(revalidated by mtime/size) and reference its content from later steps via
${{ name.content }}—textorbase64encoding. - New
std/file-write@v1action: write (or append) content to a file —
e.g. persist${{ resp.body }}to disk; base64 content is decoded before
writing. std/http@v1output now includes responseheaders(lowercase names),
and${{ ... }}paths descend nested objects — chain requests on response
headers:headers: { x-session: "${{ r1.headers.x-session }}" }.std/http@v1can sendmultipart/form-data: amultipart:array of
parts — text fields (value) and file uploads (file, with optional
filename/content_type). Mutually exclusive withbody; the boundary
header is set automatically.
Changed
- Release notes are now written by hand in
UPCOMING.mdinstead of being a
bare commit diff; the release workflow publishes and then resets the file. - Steps without
${{ ... }}placeholders skip the interpolation pass
entirely — no per-iteration deep clone of thewith:block on the hot
path. The${{ ... }}variable syntax is now fully documented in the
YAML reference. - The native engine tracks request durations in a fixed-size HDR histogram
(~tens of KB) instead of storing every sample: long soak runs no longer
grow memory 8 bytes per request (a 30-hour run at 10k RPS previously
needed ~26 GB at the final summary). Quantiles are now within ≤1% of the
exact value — invisible at the precision the summary prints. - The step engine exposes an
ActionHandlerregistration seam
(register_action) so downstream builds can add custompro/*actions
without forking; built-instd/*actions pay no lookup cost for it.
Full Changelog: v0.3.0...v0.4.0
v0.3.0
v0.2.0
v0.1.0
Full Changelog: https://github.com/Perfscale/perfscale/commits/v0.1.0