Skip to content

perf: write captured stdout/stderr straight to the output file - #2973

Merged
acozzette merged 2 commits into
aspect-build:mainfrom
acozzette:stdout-stderr-capture
Aug 14, 2026
Merged

perf: write captured stdout/stderr straight to the output file#2973
acozzette merged 2 commits into
aspect-build:mainfrom
acozzette:stdout-stderr-capture

Conversation

@acozzette

Copy link
Copy Markdown
Contributor

It is advantageous to write the captured stderr or stdout straight to its intended destination. This eliminates a cleanup step after Node exits, making it possible to invoke Node via exec and thus avoid forking an extra process.

There is a drawback, which is that if the action fails then the captured output will be lost, making it somewhat harder to troubleshoot. This seems like an acceptable cost given the performance benefit, though.

One other caveat is that we can only do this when silent_on_success is not enabled, but that parameter defaults to True for js_run_binary. Under the default behavior, we have to store stdout and stderr in temporary files so that we are prepared to print them out if the action fails. So to get any improvement from this change, the action has to opt in by setting silent_on_success = False, or else invoke the js_binary without using js_run_binary.

This commit makes one other significant change, which is to always print out the launcher script's fatal- and error-level log messages instead of capturing them. This behavior is logical because if such a message is getting logged then the action is almost certainly going to fail, in which case there is no point in attempting to capture the log message anyway. We might as well print out the message to help the user understand what went wrong.


Changes are visible to end-users: no (except that build output may be different in some unusual cases when an action fails)

Test plan

  • Covered by existing test cases

@acozzette
acozzette marked this pull request as ready for review August 14, 2026 15:25
@acozzette
acozzette requested a review from jbedard August 14, 2026 15:25

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 61ebeeccf3

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread js/private/js_binary.sh.tpl
@acozzette
acozzette force-pushed the stdout-stderr-capture branch from 61ebeec to 30e8f6d Compare August 14, 2026 16:55
Comment thread js/private/js_binary.sh.tpl Outdated
Comment thread js/private/js_binary.sh.tpl
acozzette and others added 2 commits August 14, 2026 13:26
Pure code motion in the js_binary launcher, split out to keep the
following commit reviewable. The --bazel-bindir block and the
resolve_capture_path helper with its three call sites move up to the
top of the script, ahead of the stdout/stderr capture setup, so that the
absolute capture paths are known before anything is logged.

Neither block depends on runfiles initialization, and
resolve_capture_path still resolves against $PWD before any cd, so the
values it produces are unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The launcher buffered node's stdout and stderr in mktemp files and only
copied them to the js_run_binary(stdout, stderr) outputs from an EXIT
trap. Because work had to happen after node exited, the launcher could
not exec node: it backgrounded node, installed signal forwarding traps
and waited on it, keeping an extra shell alive for the whole action and
proxying signals and terminal control through it.

The exec fast path was in practice dead code for build actions, since
js_run_binary(silent_on_success) defaults to True and that alone forced
both temp captures to be allocated.

Point the capture at the declared output file and let node write it
directly. A mktemp is now used only when silent_on_success is set and
there is no output file to write to, which is the only case left that
needs post-processing; it is flagged with STD*_CAPTURE_IS_TEMP and is
the only thing that blocks the exec.

A stream captured to an output file is therefore no longer echoed back,
neither on a build failure nor when silent_on_success is False. Bazel
discards the output file of a failed action, so launcher FATAL and ERROR
diagnostics now go to the real stderr instead of into that file; INFO
and DEBUG logs stay with the captured stderr they annotate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@acozzette
acozzette force-pushed the stdout-stderr-capture branch from dca6790 to 9afffdb Compare August 14, 2026 20:27
@acozzette
acozzette merged commit 8c1eeb3 into aspect-build:main Aug 14, 2026
166 checks passed
@acozzette
acozzette deleted the stdout-stderr-capture branch August 14, 2026 21:42
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.

2 participants