apache / apache/shenyu

[BUG] — `HierarchicalWheelTimer`: non-daemon worker thread never stopped on `shutdown()` + unbounded single-thread task executor

Open
#6,668 2 comments 0 reactions 0 assignees View on GitHub
priority: high type: performance
Dominant language
Java
Stars
8.8k
Forks
3.1k
Avg merge
7d 1h
Merged PRs (30d)
85

Description

- severity: High (leak) / Medium (bottleneck)
- files: `shenyu-common/src/main/java/org/apache/shenyu/common/timer/HierarchicalWheelTimer.java:83-86` (`ShenyuThreadFactory.create(executorName, false)` → non-daemon), `:84-85` (`taskExecutor = new ThreadPoolExecutor(1,1,0L,MS,new LinkedBlockingQueue<>())`), `:146-148` (`shutdown` only stops `taskExecutor`, never `workerThread`), `:164-170` (`Worker.run` `while(true)` swallows `InterruptedException`)
- description: `shutdown()` never stops/interrupts the non-daemon `workerThread`, so its `while(true)` loop keeps running and ignores interrupts → thread leak + JVM hangs on redeploy. All expired timer tasks run on a single-thread executor with an *unbounded* `LinkedBlockingQueue` → burst of simultaneous expirations or any slow task creates head-of-line blocking and unbounded queue growth. Used by `FailbackRegistryRepository` (client) and `FallbackShenyuClientRegisterService` (admin).
- impact: Leaked non-daemon thread on redeploy; retry backpressure bottleneck.
- suggested_fix: Make `workerThread` a daemon (or interrupt+join in `shutdown`); bound `taskExecutor`'s queue with a real rejection handler.
- confidence: High

---
_Identified during the 2026-08-02 deep re-scan; full list in [`docs/scan2-2026-08-02/00-consolidated-critical-high.md`](docs/scan2-2026-08-02/00-consolidated-critical-high.md)._

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with shenyu-common/src/main/java/org/apache/shenyu/common/timer/HierarchicalWheelTimer.java, especially the constructor lines 83-86, shutdown at 146-148, and Worker.run at 164-170. Trace its use from FailbackRegistryRepository and FallbackShenyuClientRegisterService, then define and verify shutdown behavior and bounded executor backpressure. Done means shutdown no longer leaves the worker running and expired-task bursts cannot grow an unbounded queue.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.