Aias00 opened a new issue, #7714:
URL: https://github.com/apache/shenyu/issues/7714

   ### Current behavior
   
   The request path lazily initializes selector-specific cache backends using a 
non-atomic `get` followed by `init`. Two first requests can both observe no 
cache and both build a backend. `ApplicationConfigCache.init()` unconditionally 
`put`s the result; the overwritten backend is never closed.
   
   ### Locations / flow
   
   - 
[CachePlugin.getCache():122–130](https://github.com/apache/shenyu/blob/66d7d954ca37d651a5ad916f988a8081157a7ab4/shenyu-plugin/shenyu-plugin-cache/shenyu-plugin-cache-handler/src/main/java/org/apache/shenyu/plugin/cache/CachePlugin.java#L122)
   - 
[ApplicationConfigCache.init():42–49](https://github.com/apache/shenyu/blob/66d7d954ca37d651a5ad916f988a8081157a7ab4/shenyu-plugin/shenyu-plugin-cache/shenyu-plugin-cache-handler/src/main/java/org/apache/shenyu/plugin/cache/cache/ApplicationConfigCache.java#L42)
   - `CachePluginDataHandler` invalidates selector backends on configuration 
changes, making first-request initialization reachable again after updates.
   
   ### Reproduction / validation
   
   A probe compiled the current CachePlugin, ApplicationConfigCache and 
required cache helpers. It registered a small SPI backend whose builder used a 
barrier to hold two simultaneous first requests after their empty lookup; the 
backend only tracked creation/close calls and did not contact Redis. It invoked 
the actual private `getCache()` helper concurrently, then invalidated the 
selector:
   
   ```text
   LAZY_BUILDS=2 DIFFERENT_INSTANCES=true CLOSED_BEFORE_INVALIDATE=0
   CLOSED_AFTER_INVALIDATE=1 CREATED=2
   ```
   
   The factory map owned only the winning instance; normal invalidation closed 
only that instance, leaving the overwritten backend unclosed. An independent 
reviewer confirmed the production lazy-init/update paths. No claim is made that 
a real Redis pool count was measured; RedisCache owns a factory that needs 
explicit cleanup, so the ownership loss is relevant for that backend.
   
   ### Impact / expected behavior
   
   Concurrent initial traffic and repeated selector updates can leak backend 
clients/pools and give simultaneous requests different supposedly 
selector-scoped caches. Each constructed backend should have a single tracked 
owner and a deterministic close path.
   
   ### Suggested fix
   
   Coordinate initialization atomically per selector and close any 
replaced/unused instance safely. Also audit `invalidateCache()`'s separate 
get/close/remove operations so an older invalidation cannot remove a 
concurrently installed replacement. Preserve in-flight request safety during 
handoff rather than simply closing arbitrary instances.
   
   ### Related existing work
   
   #7156 covers missing cleanup on Redis configuration replacement. #7163 
covers plugin-global replacement ordering and handler removal. This issue is 
specifically request-driven per-selector get-then-init creating multiple owners 
for the same key. #3548 concerns a blocking Redis call on Reactor threads. None 
describes this reproduced per-selector initialization race.
   
   
   ### Reviewed revision
   
   Apache ShenYu 2.7.2-SNAPSHOT, 
`master@66d7d954ca37d651a5ad916f988a8081157a7ab4`. Severity Medium / P2; 
confidence high. Unit-test and CI issue categories excluded.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to