Skip to content

fix: feign RepeatedCollectManager depth leak causing record miss (#587)#622

Merged
zwobill merged 1 commit into
arextest:mainfrom
DZQOX:fix/587-feign-repeatedcollect-symmetry
Jul 16, 2026
Merged

fix: feign RepeatedCollectManager depth leak causing record miss (#587)#622
zwobill merged 1 commit into
arextest:mainfrom
DZQOX:fix/587-feign-repeatedcollect-symmetry

Conversation

@DZQOX

@DZQOX DZQOX commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Fix #587 — under mixed record/replay traffic on the same thread, some requests silently fail to record (issue reports ~10% failure rate; user observed CallDepth reaching 9 while a normal call chain tops out at 4). Root cause is unbalanced RepeatedCollectManager.enter() / exitAndValidate() in the Feign advice.

Root cause

In FeignClientInstrumentation.ExecuteAdvice:

  • onEnter calls RepeatedCollectManager.enter() unconditionally when needRecordOrReplay()
  • onExit returns early inside the mockResult != null && notIgnoreMockResult() branch, without calling exitAndValidate()

Every replay-hit request therefore leaks +1 on the thread-local CallDepth. Once depth passes 1, subsequent record attempts on the same thread see exitAndValidate() == false and are dropped. This explains the "10% requests not recorded / depth up to 9" symptom in the issue.

There's also a latent bug in the same code path: nested http clients (e.g. Feign wrapping Apache HttpClient via feign-httpclient) both try to replay, and the inner client re-consumes the request body — leading to replay-match misses.

Changes

FeignClientInstrumentation.java:

  1. outermost check moved before enter() — capture boolean isOutermost = RepeatedCollectManager.validate() first, so a nested call detects it's inside an already-entered scope and skips its own replay.
  2. replay gated on isOutermost — inner nested clients no longer double-consume the request body.
  3. exitAndValidate() called unconditionally at top of onExit — mock hits now decrement CallDepth too, keeping enter/exit balanced. The saved isOutermost is used for the record gate.

FeignClientInstrumentationTest.java:

  • add stub for RepeatedCollectManager.validate() in the existing replay-path assertion
  • add a nested-call case asserting inner replay is skipped when outer already entered

Test plan

…xtest#587)

onEnter unconditionally called RepeatedCollectManager.enter() but onExit
skipped exitAndValidate() when a mock result was returned, so CallDepth
kept growing across replay-hit requests. Once depth passed 1, subsequent
record attempts on the same thread saw exitAndValidate()==false and were
silently dropped (issue arextest#587 reports depth reaching 9 while normal is 4).

- move outermost check (validate()) before enter() so nested http clients
  (e.g. Feign -> Apache) skip inner replay and avoid request body double
  consumption
- call exitAndValidate() unconditionally in onExit to keep enter/exit
  balanced regardless of mock hit
- update tests to cover the nested-call skip path
@DZQOX
DZQOX force-pushed the fix/587-feign-repeatedcollect-symmetry branch from 48e0eee to 794f6c9 Compare July 16, 2026 05:19
@zwobill
zwobill enabled auto-merge (squash) July 16, 2026 05:55
@sonarqubecloud

Copy link
Copy Markdown

@zwobill
zwobill merged commit f9d7688 into arextest:main Jul 16, 2026
7 checks passed
@DZQOX
DZQOX deleted the fix/587-feign-repeatedcollect-symmetry branch July 16, 2026 09:02
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.

[Bug] 存在10%的录制请求没有录制成功的情况。

3 participants