AlexStocks opened a new issue, #3555:
URL: https://github.com/apache/dubbo-go/issues/3555

   ## Description
   
   Several goroutines and retry loops have no cancellation / context-exit path, 
so they can leak or block indefinitely when the component is shutting down or 
the upstream is unavailable.
   
   ## Affected locations
   
   ### 1. `cluster/cluster/failback/cluster_invoker.go` — `process` (L94-L121)
   
   ```go
   func (invoker *failbackClusterInvoker) process(ctx context.Context) {
       invoker.ticker = time.NewTicker(time.Second * 1)
       for range invoker.ticker.C {            // L96: no ctx.Done() branch
           for {
               value, err := invoker.taskList.Peek()
               if err == queue.ErrDisposed { return }
               ...
               go invoker.tryTimerTaskProc(ctx, retryTask)   // L118
           }
       }
   }
   ```
   
   - `ctx` is passed in but never selected on; the only exit is 
`taskList.Dispose()`.
   - The ticker has no `defer invoker.ticker.Stop()`.
   - Risk: if `Dispose` is never called, the goroutine (and the ticker) leak 
for the process lifetime.
   
   ### 2. `registry/base_registry.go` — `Subscribe` (L330-L347)
   
   ```go
   for {                                    // L330: no ctx exit
       if !r.IsAvailable() { return ... }
       listener, err := r.facadeBasedRegistry.DoSubscribe(url)
       if err != nil { time.Sleep(...); continue }  // L343: unbounded retry, 
no ctx cancel
       for { ... }                         // L347: inner loop also has no ctx
   }
   ```
   
   - No upper bound on retries; cannot be cancelled by an external `context`.
   - Risk: a permanently unavailable registry causes an infinite blocking retry 
loop.
   
   ### 3. `remoting/getty/pool.go` — connect loop (L81-L97)
   
   ```go
   for {
       idx++
       if c.isAvailable() { break }
       if time.Since(start) > connectTimeout { ... return }
       interval := time.Millisecond * time.Duration(idx)
       time.Sleep(interval)                // L96: blocks; cannot react to ctx 
cancel
   }
   ```
   
   - Uses `time.Sleep` polling instead of `select` + `ctx.Done()`; a cancelled 
context still waits for the sleep to return.
   - Risk: connection attempts cannot be interrupted promptly.
   
   ## Suggested fix
   
   - `failback`: `defer invoker.ticker.Stop()`; add `select { case 
<-ctx.Done(): return; case <-invoker.ticker.C: ... }`.
   - `base_registry`: select on `ctx.Done()` in the retry loops and return on 
cancellation.
   - `getty/pool`: replace the `time.Sleep` polling with `select { case 
<-ctx.Done(): return; case <-time.After(interval): }`.
   
   ## Severity
   
   P0/P1 — goroutine leak + non-cancellable retry loops affect long-running 
service stability.
   
   ## Environment
   
   - Reproducible on current `develop` tip (3.3.2 prep).
   


-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to