Skip to content

feat(http-client): flag N+1 outgoing calls by URL shape - #84

Merged
sylvesterdamgaard merged 1 commit into
mainfrom
feat/http-client-n-plus-one
Oct 13, 2026
Merged

sylvesterdamgaard merged 1 commit into
mainfrom
feat/http-client-n-plus-one

Conversation

@sylvesterdamgaard

Copy link
Copy Markdown
Contributor

Flags an N+1 of outgoing HTTP calls (one endpoint fetched once per id, one call after another), the way an N+1 query is already flagged.

How it works

  • Shape = method + host(:port) + path with id-like segments as {id} + sorted query param names (values dropped). Ids are numbers/dates, UUIDs, ULIDs, 16+ hex digests, Stripe-style prefixed tokens, long letter+digit tokens and emails. v2, oauth2 and other names are left alone. Support\HttpShape is the HTTP twin of SqlShape.
  • N+1 = same shape, different URLs, sequential, threshold (default 3) times in one trace. GET/HEAD only. Not flagged: pagination (page, cursor, offset, after/before, starting_after, pageToken, page[...], /page/2, ...), repeats of the same exact URL (retries), and calls sent together through Http::pool (a hop that starts while another of its shape is still in flight isn't counted).
  • Signals, matching the DB ones: http.client.n_plus_one_detected event (once per shape per trace, includes url.template, url.full, shape, http.client.repeat_count, code.*), http.client.requests.n_plus_one{server.address} counter (host label goes through the classifier), http.client.n_plus_one.count root tally. Client spans get url.template and laravel.http.client.shape. From the crossing call on, they also get laravel.http.client.repeat = "n_plus_one". Tail detail mode keeps these traces.
  • Config: instrument.http_client_n_plus_one (on), ..._threshold (3), instrument.http_client_origin (flagged/all/off). When detection is off, no detector is built and nothing gets shaped.

Costs about 2 µs per hop (measured). The shape comes from the request as the app built it. A withRequestMiddleware() URL rewrite isn't reflected in it.

Tests cover the shape edge cases, pagination, pool, same-URL, writes, threshold, origin modes, trace reset and tail retention. composer check is green.

https://claude.ai/code/session_01LtsaMBeethcCYvKx8PTBYL

One endpoint called once per id, one call after another, within one
trace is flagged like an N+1 query. Calls are shaped as method + host +
path with id-like segments as {id} + query parameter names. Reads only;
pagination, repeats of the same URL and Http::pool batches are excluded.
Adds the http.client.n_plus_one_detected event, the
http.client.requests.n_plus_one counter, the http.client.n_plus_one.count
root tally, url.template / laravel.http.client.shape /
laravel.http.client.repeat span attributes, code.* origin and tail-mode
retention.

Claude-Session: https://claude.ai/code/session_01LtsaMBeethcCYvKx8PTBYL
@sylvesterdamgaard
sylvesterdamgaard force-pushed the feat/http-client-n-plus-one branch from 4d73784 to 26d9d4f Compare October 13, 2026 14:08
@sylvesterdamgaard
sylvesterdamgaard merged commit 905ee82 into main Oct 13, 2026
16 checks passed
@sylvesterdamgaard
sylvesterdamgaard deleted the feat/http-client-n-plus-one branch October 13, 2026 14:10
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.

1 participant