Skip to content

fix(processor): propagate async ResultMessage HTTP status to batch#590

Merged
j-mok-dev merged 1 commit into
mainfrom
feat-589-async-status-code
Jul 16, 2026
Merged

fix(processor): propagate async ResultMessage HTTP status to batch#590
j-mok-dev merged 1 commit into
mainfrom
feat-589-async-status-code

Conversation

@j-mok-dev

Copy link
Copy Markdown
Collaborator

Why is this PR needed?

When dispatchMode: async, HTTP error statuses from the async-processor (e.g. 403 with an empty body) were lost on the batch-gateway consumer side. Batch output then reported parse_error instead of preserving status_code: 403, which broke sync/async parity for authorization failures.
Upstream llm-d-async already returns ResultMessage.StatusCode / error fields (llm-d/llm-d-async#298). This PR consumes those fields.

What does this PR do?

  • Add StatusCode, ErrorCode, and ErrorMessage to GenerateResponse
  • Propagate those fields from ResultMessage in GetResult()
  • Update asyncResult() to:
    • use the real HTTP status instead of hardcoding 200
    • preserve non-2xx status even when the body is empty or non-JSON
    • map non-HTTP failures (StatusCode == 0 + error metadata) to output errors
    • treat legacy payloads with no status as HTTP 200
  • Unit coverage for status/error propagation
  • Dispatcher e2e (HTTPErrorStatusPreserved) using a consumer-less sim-pool-inject pool so a synthetic ResultMessage{StatusCode: 403, Payload: ""} can be injected without racing the async-processor (Kind has no AuthPolicy)

How was this tested?

  • Unit tests added/updated/verified
  • Integration/e2e tests added/updated/verified
  • Manual testing performed

Checklist

  • Commits are signed off (git commit -s) per DCO
  • Code follows project contributing guidelines
  • Pre-commit checks pass (make pre-commit)
  • Unit tests pass (make test)
  • E2E tests pass (make test-e2e)

Related Issues

Fixes #589

DISPATCHER_VERSION="${DISPATCHER_VERSION:-v0.7.3}"
_ASYNC_MOD_VERSION=$(grep 'llm-d-async/api' "${REPO_ROOT}/go.mod" | awk '{print $2}')
DISPATCHER_VERSION="${DISPATCHER_VERSION:-${_ASYNC_MOD_VERSION}}"
DISPATCHER_IMAGE="${DISPATCHER_IMAGE:-ghcr.io/llm-d-incubation/llm-d-async:${DISPATCHER_VERSION}}"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

chart and image not changed after graduation?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The v0.7.4 container image hasn't been published yet — the release workflow failed The chart OCI path at ghcr.io/llm-d/charts/async-processor also returns 404 currently.
Once the upstream image is available at ghcr.io/llm-d/llm-d-async:v0.7.4, I'll update the script to point there. Keeping it at the working v0.7.3 incubation path for now so dev-deploy and e2e don't break.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

it seems chart has moved

# helm show chart oci://ghcr.io/llm-d-incubation/charts/async-processor --version 0.7.4
Error: failed to perform "FetchReference" on source: ghcr.io/llm-d-incubation/charts/async-processor:0.7.4: not found

# helm show chart oci://ghcr.io/llm-d/charts/async-processor --version 0.7.4
Pulled: ghcr.io/llm-d/charts/async-processor:0.7.4
Digest: sha256:34023f82d2a40f245b1f1ebebfaeaa5e721190582d8016594fa6a6ff7989e195
apiVersion: v2
appVersion: v0.7.4
description: Helm chart for Async-Processor (AP) - Asynchronous Processor for LLM
  inference workloads
name: async-processor
type: application
version: 0.7.4

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

maybe stay with 0.7.3 and we merge this
once they fixed 0.7.4, we upgrade

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.

yes if we can stay on 0.7.3 (pre-rename?) the diff should be smaller as swell

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Thanks @evacchi @yizhaodev I've dropped the v0.7.4 upgrade commit from this branch.
This PR now only contains the status-code propagation fix + e2e test. Will open a follow-up PR for the module migration once the upstream image is published.

@evacchi evacchi left a comment

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.

only a nit, other than that 👍

result.Error = &OutputError{Code: "server_error", Message: "async response has no body"}

// Non-HTTP failure: StatusCode == 0 with error metadata from llm-d-async.
if resp.StatusCode == 0 && (resp.ErrorCode != "" || resp.ErrorMessage != "") {

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.

maybe let's turn this into a predicate on ResponseItem

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Thanks! added IsNonHTTPFailure() on GenerateResponse and switched the callsite to use it.

…tput

Async dispatch discarded ResultMessage.StatusCode and hardcoded 200, so
auth failures (e.g. 403 with empty body) became parse_error instead of
preserving the real status. Propagate status/error fields through
GetResult and asyncResult, and cover with unit + dispatcher e2e.

Fixes #589

Signed-off-by: Jooyeon Mok <jmok@redhat.com>
@j-mok-dev
j-mok-dev force-pushed the feat-589-async-status-code branch from b310e20 to f458e6b Compare July 16, 2026 18:27
@j-mok-dev
j-mok-dev merged commit 17ab15d into main Jul 16, 2026
6 checks passed
@j-mok-dev
j-mok-dev deleted the feat-589-async-status-code branch July 16, 2026 18:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Fixes incorrect behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Async dispatch does not propagate HTTP status code from async-processor result

3 participants