Skip to content

Phase 2: HTTPXWrapper initial implementation#22704

Draft
mwdd146980 wants to merge 1 commit intographite-base/22704from
mwdd146980/phase2-httpx-wrapper
Draft

Phase 2: HTTPXWrapper initial implementation#22704
mwdd146980 wants to merge 1 commit intographite-base/22704from
mwdd146980/phase2-httpx-wrapper

Conversation

@mwdd146980
Copy link
Copy Markdown
Contributor

@mwdd146980 mwdd146980 commented Feb 20, 2026

What does this PR do?

Implements Phase 2 of the requests → httpx migration (Phase 1: PR #22676).

New: http_httpx.py

  • HTTPXWrapper — wraps httpx.Client, satisfies HTTPClientProtocol, translates httpx exceptions to the HTTPError hierarchy
  • HTTPXResponseAdapter — bridges httpx.Response to HTTPResponseProtocol: adds iter_content (httpx uses iter_bytes/iter_text), adapts iter_lines signature, and adds __enter__/__exit__ (httpx responses aren't context managers)
  • Exception translation at the request boundary: httpx.TimeoutExceptionHTTPTimeoutError, httpx.ConnectErrorHTTPConnectionError, etc.

New: use_httpx feature flag in AgentCheck.http

  • Set use_httpx: true in instance config to opt a check into the httpx backend
  • All integrations using self.http get the flag for free; no call-site changes required
  • Default remains RequestsWrapper

Proof of concept: nginx

  • test_get_enabled_endpoints and test_only_query_enabled_endpoints now run with both [requests] and [httpx] backends — all pass
  • Tests that patch requests.Session directly (test_config, test_no_version) are left on the requests backend; they document the config parity gap (auth/SSL forwarding to httpx.Client) deferred to Phase 3

Backend equivalence tests

  • test_http_backend_equivalence.py: RequestsWrapper and HTTPXWrapper produce identical responses for status_code, content, iter_lines, iter_content, and context manager usage

Known limitations (Phase 3 work)

HTTPXWrapper currently wraps a plain httpx.Client(). Instance config options (auth, TLS, proxy, timeouts) are not yet forwarded to the httpx client. Integrations that rely on test_config-style assertions against requests.Session kwargs will need per-integration follow-up once config parity is implemented.

Motivation

RFC: Migrate the HTTP layer from requests to httpx

Phase 1 established the protocol boundary. Phase 2 provides the httpx implementation and the opt-in mechanism.

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Add the qa/skip-qa label if the PR doesn't need to be tested during QA.
  • If you need to backport this PR to another branch, you can add the backport/<branch-name> label to the PR and it will automatically open a backport PR once this one is merged

@mwdd146980 mwdd146980 changed the title Phase 2: HTTPXWrapper implementation Phase 2: HTTPXWrapper initial implementation Feb 20, 2026
Copy link
Copy Markdown
Contributor Author

mwdd146980 commented Feb 20, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@codecov
Copy link
Copy Markdown

codecov bot commented Feb 20, 2026

Codecov Report

❌ Patch coverage is 97.12919% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.55%. Comparing base (88dfb33) to head (3cf3aa0).

Additional details and impacted files
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mwdd146980
Copy link
Copy Markdown
Contributor Author

Code review

Found 2 issues:

  1. Non-HTTPError httpx exceptions (e.g. httpx.InvalidURL) bypass the translation layer and leak as raw httpx exceptions. _request only catches httpx.HTTPError, but httpx.InvalidURL inherits directly from Exception — not from httpx.HTTPError. A malformed URL in instance config will surface as a raw httpx.InvalidURL rather than an HTTPError subclass, breaking any caller that catches the project's exception hierarchy.

def _request(self, method: str, url: str, **options: Any) -> HTTPXResponseAdapter:
try:
return HTTPXResponseAdapter(self._client.request(method, url, **options))
except httpx.HTTPError as e:
raise _translate_httpx_error(e) from e

  1. HTTPXWrapper never closes its httpx.Client, leaking file descriptors in long-running Agent processes. HTTPXWrapper has no close() method or __enter__/__exit__, and AgentCheck has no teardown that releases self._http. RequestsWrapper handles this via __del__ calling self._session.close() (see http.py L639–645), but the httpx wrapper has no equivalent. httpx.Client pools connections and requires explicit cleanup.

class HTTPXWrapper:
def __init__(self, client: httpx.Client) -> None:
self._client = client

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@mwdd146980 mwdd146980 force-pushed the mwdd146980/phase2-httpx-wrapper branch from d4075a6 to df634c5 Compare February 23, 2026 14:24
@mwdd146980 mwdd146980 force-pushed the mwdd146980/httpx-migration-base branch from 97854d1 to 8fc9e4f Compare February 23, 2026 14:24
@mwdd146980 mwdd146980 force-pushed the mwdd146980/phase2-httpx-wrapper branch from df634c5 to c95925b Compare February 23, 2026 14:47
@mwdd146980 mwdd146980 changed the base branch from mwdd146980/httpx-migration-base to graphite-base/22704 February 23, 2026 16:55
@mwdd146980 mwdd146980 force-pushed the mwdd146980/phase2-httpx-wrapper branch from c95925b to cdd0d69 Compare February 25, 2026 02:29
@mwdd146980 mwdd146980 changed the base branch from graphite-base/22704 to mwdd146980/phase1b-test-decoupling February 25, 2026 02:29
@mwdd146980 mwdd146980 changed the base branch from mwdd146980/phase1b-test-decoupling to graphite-base/22704 February 25, 2026 17:19
@mwdd146980 mwdd146980 force-pushed the graphite-base/22704 branch from 05fc099 to 54aa5eb Compare March 2, 2026 22:07
@mwdd146980 mwdd146980 force-pushed the mwdd146980/phase2-httpx-wrapper branch from cdd0d69 to 654cd59 Compare March 2, 2026 22:07
@mwdd146980 mwdd146980 changed the base branch from graphite-base/22704 to mwdd146980/httpx-migration-base March 2, 2026 22:07
@datadog-official

This comment has been minimized.

@mwdd146980 mwdd146980 force-pushed the mwdd146980/phase2-httpx-wrapper branch from 654cd59 to 6cc127d Compare March 2, 2026 22:53
httpx was already present transitively via httpx-gssapi/ntlm/kerberos.
Declaring it explicitly pins the version and signals intent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mwdd146980 mwdd146980 force-pushed the mwdd146980/phase2-httpx-wrapper branch from 6cc127d to 3cf3aa0 Compare March 2, 2026 23:06
@mwdd146980 mwdd146980 changed the base branch from mwdd146980/httpx-migration-base to graphite-base/22704 March 5, 2026 20:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant