Skip to content

Instrument aiohttp so async apps are not silently uncovered #29

Open

Description

@guillaumegay13

The gap

docs/guide.md:72 states it plainly:

Standard httpx and httpx2 transports and requests adapters are instrumented process-wide, including existing clients. Custom transports, aiohttp, browsers and other languages are not covered.

aiohttp is the one entry on that list that is neither exotic nor out of scope. It is the default HTTP client for aiohttp-server apps, and it is what a large share of async Python reaches for. An app built on it installs the SDK, sees an empty dashboard, and concludes the product does not work.

Why it belongs with httpx and requests

The instrumentation pattern is already established in outbound.py:

Client Patch point
httpx HTTPTransport.handle_request / AsyncHTTPTransport.handle_async_request
requests requests.adapters.HTTPAdapter.send
aiohttp to determine — likely ClientSession._request

Patching at that level covers clients constructed before manifest() ran, which is the property that makes the current two work.

The async half of the loop already exists — AsyncHealApi in heal_api.py — so this is a third instrumentation module against machinery that is built, not a new capability.

Scope

Same contract as the other two clients, no exceptions:

  • capture 4xx except 401, 402, 403 and 429
  • one retry per captured failure
  • apply healedRequest url / headers / body
  • report the outcome to PATCH /v1/heal-attempts/:id
  • internal_call guard so the SDK's own calls are not captured
  • fail open: any error in the SDK returns the original response

Open questions

  1. Which method is the true funnel. ClientSession._request handles redirects and retries internally, so hooking it may capture intermediate responses that the caller never sees.
  2. Body readability. aiohttp accepts streams, FormData and async iterables as payloads. A body that cannot be read or re-encoded must be reported and never retried, as parse_request_body already decides for the other clients.
  3. Whether the connector level is a better insertion point than the session level.

Done when

  • an aiohttp request that fails with a fixable 4xx is healed and retried, with no app code change
  • clients created before manifest() ran are covered
  • unit tests match the shape of test_outbound_httpx.py
  • docs/guide.md:72 no longer lists aiohttp as uncovered
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions