[BUG] DividePlugin.beginTime is a shared mutable instance field, racy under shortestResponse load balancing
- Dominant language
- Java
- Stars
- 8.8k
- Forks
- 3.1k
- Avg merge
- 7d 9h
- Merged PRs (30d)
- 83
Description
## Description
`private Long beginTime;` is a plain instance field on the `DividePlugin` singleton bean. In the `SHORTEST_RESPONSE` branch it is set per-request (`beginTime = System.currentTimeMillis()`) and later read in `successResponseTrigger` (`upstream.getSucceededElapsed().addAndGet(System.currentTimeMillis() - beginTime)`). With concurrent requests, request B overwrites `beginTime` while request A is still in flight, so A's completion computes `now - ` — a wrong (often negative or far too small) elapsed value that is *added* to the upstream's cumulative `succeededElapsed` counter.
## Location
```
shenyu-plugin-divide/.../DividePlugin.java:63 (field), 137 (write), 197 (read in successResponseTrigger)
```
## Impact
With two or more concurrent HTTP requests matching a divide rule whose `loadBalance` is `shortestResponse`, `ShortestResponseLoadBalancer.doSelect` picks upstreams by `succeededAverageElapsed * inflight`; corrupted averages produce wrong "shortest" selections — traffic is steered to the wrong upstream. The corruption is cumulative (`addAndGet` of bad deltas), so it persists and worsens.
## Suggested fix
Do not store the start time on the singleton. Capture `start` as a local `final long` and use `chain.execute(exchange).doOnSuccess(e -> successResponseTrigger(upstream, start))`, or stash it in an exchange attribute.
## Related existing issue(s)
#6427 (closed) was about P2C EWMA decay order reversal; this is a different latency-bookkeeping race in `DividePlugin` itself, distinct.
_Identified during the 2026-08-02 audit; full list in [`docs/issue-candidates-2026-08-02.md`](docs/issue-candidates-2026-08-02.md)._
Contributor guide
No contributing guide indexed for this repository
Research direction
Read DividePlugin.java at the field and the write/read sites listed in the issue, then trace the SHORTEST_RESPONSE branch through successResponseTrigger. Check the existing tests for divide load balancing and concurrent requests. Done means each request's elapsed time is measured from its own start, without corrupting the upstream's cumulative succeededElapsed.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend-api-design
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100