Skip to content

fix(bazel): identify bazel query context timeouts wrapping the error - #246

Merged
yushan8 merged 9 commits into
mainfrom
yushan/bazel-query-context-timeout
Jul 29, 2026
Merged

fix(bazel): identify bazel query context timeouts wrapping the error#246
yushan8 merged 9 commits into
mainfrom
yushan/bazel-query-context-timeout

Conversation

@yushan8

@yushan8 yushan8 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Wrap the error if bazel query timed out so we can identify which command was attributed to context.DeadlineExceeded.

Follow-up to #236, which classified bazelisk download network failures as
retryable (a different case: that one is a genuine transient failure
before any query even starts).

Test Plan

  • Added TestExecuteQueryInternal_ContextTimeout assertion that the error
    now wraps bazel.ErrQueryTimeout.
  • Added TestExecuteQueryInternal_WaitFailureWithoutTimeout to confirm a
    plain wait failure (no context deadline) is not misclassified as a
    timeout.
  • Added TestExecuteQueryInternal_StreamTimeoutWithoutWaitError to confirm
    a timeout surfacing only via the stream-reading goroutines is still
    wrapped with ErrQueryTimeout.

Revert Plan

Revert this PR; the sentinel and its detection are removed, with no
change to runtime classification behavior.

Intent:
- A bazel query killed for exceeding its configured timeout was
  previously wrapped as a plain error, falling through to the
  ErrorInfra default in tangoerrors.GetErrorCode. A query timeout can
  be transient (a loaded machine, a cold repo cache) and is worth
  retrying, unlike a genuine query/config failure.

Changes:
- Add bazel.ErrQueryTimeout, wrapped in executeQueryInternal when
  cmd.Wait() fails and the query's own context (not a parent
  cancellation) has hit its deadline.
- Add orchestrator.classifyComputeError, classifying ErrQueryTimeout as
  tangoerrors.ErrorInfraRetryable and everything else as
  tangoerrors.ErrorInfra; wired into nativeOrchestrator's compute step.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@yushan8
yushan8 requested review from a team as code owners July 28, 2026 18:22
waitErr and streamErr are two independent consumers of cmdCtx: if the
bazel process exits cleanly right at the deadline, waitErr can be nil
while the stream-reading goroutines are still canceled mid-read via
gCtx, surfacing as streamErr instead. That path wasn't wrapped with
ErrQueryTimeout, so it fell through to the non-retryable default even
though it's the same timeout condition.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@yushan8
yushan8 marked this pull request as draft July 28, 2026 18:37
yushan8 and others added 2 commits July 28, 2026 11:41
bazel.ErrQueryTimeout exists to let callers distinguish a service-side
query timeout (ctx.Err() == DeadlineExceeded on the query's own
timeout) from a client-initiated cancellation via errors.Is, not to
drive automatic retries. Drop classifyComputeError and go back to
plain error wrapping in GetTargetGraph; the sentinel is still
reachable through the %w chain from core/bazel/query.go.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Update the doc comment left over from when this sentinel drove
retryable classification; it now exists purely so callers can tell a
service-side query timeout apart from a client cancellation via
errors.Is.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@yushan8 yushan8 changed the title fix(bazel): classify bazel query context timeouts as retryable fix(bazel): identify bazel query context timeouts via sentinel error Jul 28, 2026
@yushan8
yushan8 marked this pull request as ready for review July 28, 2026 22:52
yushan8 and others added 2 commits July 28, 2026 15:57
Both call sites needed the same two-line "if timedOut { wrap with
ErrQueryTimeout }" before calling wrapQueryFailure. Pass timedOut
through instead so the wrapping happens once, in one place.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Let wrapQueryFailure check ctx.Err() == context.DeadlineExceeded itself
rather than having the caller precompute a timedOut bool and thread it
through.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Comment thread core/bazel/query.go Outdated
// live, so it's omitted.
func (b *BazelClient) wrapQueryFailure(msg string, cause error, stderrBuf *bytes.Buffer) error {
func (b *BazelClient) wrapQueryFailure(ctx context.Context, msg string, cause error, stderrBuf *bytes.Buffer) error {
if ctx.Err() == context.DeadlineExceeded {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we should do this check, but a sentinel seems overkill since we're not handling it anywhere. A plain fmt.Errorf achieves the same result. Unless we plan to do something with it right now, I'd prefer just making it a plain error until we specifically want to handle this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That's fair. Updated.

yushan8 added 2 commits July 29, 2026 09:20
Nothing consumes it via errors.Is yet; a plain error message achieves
the same diagnostic value until a caller actually needs to branch on it.
Wrapping context.DeadlineExceeded lets tests use errors.Is instead of
matching on error text, per repo convention against string assertions.
@yushan8 yushan8 changed the title fix(bazel): identify bazel query context timeouts via sentinel error fix(bazel): identify bazel query context timeouts wrapping the error Jul 29, 2026
@yushan8
yushan8 merged commit b66c91a into main Jul 29, 2026
8 of 10 checks passed
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