Skip to content

Make upstream_response_body_filter async - #974

Open
torinnd wants to merge 2 commits into
cloudflare:mainfrom
torinnd:async-upstream-response-body-filter
Open

Make upstream_response_body_filter async#974
torinnd wants to merge 2 commits into
cloudflare:mainfrom
torinnd:async-upstream-response-body-filter

Conversation

@torinnd

@torinnd torinnd commented Aug 24, 2026

Copy link
Copy Markdown

Fixes #964.

This PR builds on #973, which adds a Criterion benchmark for upstream_response_body_filter. Both commits are included so this branch is independently mergeable. If the benchmark PR lands first, the remaining diff is the async-filter commit. I opted to not attempt to wrestle with GitHub's stacked PR functionality, and hope this format is convenient for review and merging.

ProxyHttp::upstream_response_body_filter is now async, matching request_body_filter and the response header hooks. This allows implementations to await response-body work without blocking a proxy worker.

The method otherwise keeps its existing contract:

  • body mutation is unchanged;
  • errors still propagate through the proxy loop;
  • Result<Option<Duration>> continues to control pacing;
  • the added Self::CTX: Send + Sync bound matches the trait’s other async methods.

There is one dispatch site, already in an async function, which now awaits the hook. Implementations that override the method need to add async.

The test calls the actual HttpProxy::upstream_filter dispatch path. It verifies that the hook can await, that body mutation and pacing survive the await, and that an error returned after an await propagates.

The Criterion benchmark changes from about 14 ns/call to about 21 ns/call on my machine. The broader h1/h2 measurements and caveats are in #964; I could not resolve an end-to-end difference above the noise on that setup.

Add a Criterion benchmark for the per-call cost of
ProxyHttp::upstream_response_body_filter, covering both the default
implementation and a trivial override. This provides a stable baseline
for evaluating changes to a per-body-chunk hot path.

Run with:

  cargo bench -p pingora-proxy --bench noop_body_filter
request_body_filter is async so implementors can await throttling and
offloaded work without blocking a proxy worker. Give the upstream
response body hook the same capability while preserving its existing
body mutation, error, and pacing semantics.

The signature otherwise stays the same. The Result<Option<Duration>>
pacing mechanism is untouched, and the added CTX bound matches the
trait's other async methods. The single dispatch site is already in an
async function and now awaits the hook.

Update the response-body-filter benchmark for the async signature. A
focused test calls the real HttpProxy dispatch path and verifies that it
awaits the hook, preserves body mutation and pacing, and propagates an
error returned after an await.
@torinnd
torinnd force-pushed the async-upstream-response-body-filter branch from 13a07cb to db63a23 Compare August 27, 2026 13:13
@andrewhavck andrewhavck self-assigned this Aug 27, 2026
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.

Make upstream_response_body_filter async, like its request-side counterpart

2 participants