Skip to content

Move display out of the run data into views - #621

Open
dnagoda wants to merge 1 commit into
dc.batch-jsonlfrom
dc.batch-hot-path
Open

dnagoda wants to merge 1 commit into
dc.batch-jsonlfrom
dc.batch-hot-path

Conversation

@dnagoda

@dnagoda dnagoda commented Oct 1, 2026 •

Copy link
Copy Markdown

Stacked on #620. Review #619 and #620 first.

Why

BytesContainer::new pretty-printed every input and every output into a humanized string. Only the default text report shows that string. Batch mode and --json never do. run also deep-copied the whole input container, including that string, for the I/O handler, which reads only the raw bytes. For large inputs, most of the time per input went to building and copying data that was then dropped.

--batch, release build, Apple M4 Pro, best of 3. noop.wasm echoes its input, so the output is as large as the input:

Input size Inputs #620 This PR Change
10 B (exit_code.wasm) 10,000 0.44 s 0.44 s 0%
197 B 10,000 0.52 s 0.48 s -8%
1.9 KB 10,000 1.08 s 0.83 s -23%
20 KB 10,000 6.95 s 4.19 s -40%
103 KB 2,000 6.60 s 3.86 s -42%

The saving grows with input and output size. A Function with a small output saves less, because only the input-side work goes away.

What

BytesContainer and FunctionRunResult now hold only data. A new public views module builds output from them when it is displayed:

  • ReadableBytes::from(&container): readable text for an input or an output (pretty JSON, a hex dump for the Raw codec, or lossy UTF-8 for output that does not decode). It replaces the humanized field.
  • TextReport::from(&result): the default CLI report. It replaces the Display implementation on FunctionRunResult, and the report text does not change.
  • JsonReport::from(&result): the --json output. It uses the result's serde serialization and replaces FunctionRunResult::to_json. FunctionRunResult and BytesContainer keep Serialize and Deserialize.

The run also does less copying:

  • Parsed JSON values move into the container instead of being cloned.
  • IOHandler borrows the input container instead of taking a copy.
  • The Function output bytes go to BytesContainer::new without a copy.

Breaking changes (10.0.0)

This removes public items, so the version is 10.0.0. The README has an "Upgrading to 10.0" section.

9.x 10.0
container.humanized ReadableBytes::from(&container).to_string()
result.to_string() or format!("{result}") TextReport::from(&result).to_string()
result.to_json() JsonReport::from(&result).to_string()
  • BytesContainer::raw keeps the bytes of an output that does not decode. In 9.x it was empty.
  • The unused InvalidOutput type and the clap::ValueEnum derive on Codec are removed.

Behavior

CLI output is byte-for-byte identical to #620 for noop, exit_code, js_function, js_function_javy_plugin_v3, messagepack-valid, messagepack-invalid, and log_truncation_function, in text and --json modes. Batch output is identical with and without --batch-full-output and --batch-continue-on-error. There is one exception:

  • An output that is not valid JSON or MessagePack now keeps its raw bytes, so "Output Size" shows the real size: messagepack-invalid.wasm shows 10B where it showed 0B.

Shopify CLI runs the function-runner binary and parses only --json output, which does not change. It pins function-runner 9.2.2, so it needs a version bump to pick this up.

Not changed

Batch output still flushes after each record. A BufWriter saved about 11% on 10,000 tiny records, but then a caller that writes one input and waits for its record would block. Records must arrive as soon as each input completes.

Testing

  • cargo test --locked: 39 unit tests and 36 integration tests pass; one existing test remains ignored.
  • The three report tests move to src/views.rs. New tests cover pretty JSON, the Raw hex dump, undecodable output, and JsonReport matching serde output.
  • cargo clippy --locked -- -D warnings and cargo fmt --all -- --check pass.
  • Output comparison with Add batch mode for JSON Lines inputs #620, as described above.

@dnagoda
dnagoda force-pushed the dc.batch-hot-path branch from 8c1ad74 to f884e8f Compare October 1, 2026 21:52
@dnagoda
dnagoda added this pull request to stack #622 October 2, 2026 16:05
@dnagoda
dnagoda force-pushed the dc.batch-hot-path branch from f884e8f to e9ec4d1 Compare October 2, 2026 16:13
@dnagoda
dnagoda force-pushed the dc.batch-hot-path branch from e9ec4d1 to 57ff6af Compare October 2, 2026 16:35
@dnagoda
dnagoda force-pushed the dc.batch-hot-path branch 2 times, most recently from 1488364 to fa8ae9d Compare October 2, 2026 16:56
@dnagoda
dnagoda marked this pull request as ready for review October 2, 2026 16:59
@dnagoda
dnagoda requested a review from a team as a code owner October 2, 2026 16:59
@dnagoda
dnagoda requested review from makrisoft and removed request for a team October 2, 2026 16:59
@dnagoda
dnagoda force-pushed the dc.batch-hot-path branch from fa8ae9d to ac5ca3d Compare October 2, 2026 21:35
@dnagoda dnagoda changed the title Build the readable input and output text only when it is shown Move display out of the run data into views Oct 2, 2026
`BytesContainer::new` pretty-printed every input and output into a
`humanized` string, and `run` deep-copied the input container for the
I/O handler. Batch mode and `--json` never show that text, so for large
inputs most of the time per input went to building and copying data
that was then dropped.

`BytesContainer` and `FunctionRunResult` now hold only data. A new
public `views` module builds output from them on demand:

- `ReadableBytes` gives the readable text for an input or an output. It
  replaces the `humanized` field.
- `TextReport` is the default CLI report. It replaces the `Display`
  implementation on `FunctionRunResult`.
- `JsonReport` is the `--json` output. It uses the result's serde
  serialization and replaces `FunctionRunResult::to_json`.

The run also does less copying:

- Move parsed JSON values into the container instead of cloning them.
- `IOHandler` borrows the input instead of taking a deep copy.
- Pass the Function output bytes to the container without a copy.

An output that is not valid JSON or MessagePack now keeps its raw bytes,
so "Output Size" shows the real size instead of 0B.

This removes public items, so the version is 10.0.0. The unused
`InvalidOutput` type and the `clap::ValueEnum` derive on `Codec` are
removed too. The README lists the replacements.
@dnagoda
dnagoda force-pushed the dc.batch-hot-path branch from ac5ca3d to 9ba2354 Compare October 6, 2026 21:34
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