apache / apache/shenyu

[BUG] DividePlugin.beginTime is a shared mutable instance field, racy under shortestResponse load balancing

Open Beginner friendly
#6,544 1 comment 0 reactions 0 assignees View on GitHub
plugin: divide priority: high type: bug
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.