Copilot commented on code in PR #1163:
URL: 
https://github.com/apache/skywalking-banyandb/pull/1163#discussion_r3370381871


##########
fodc/agent/internal/proxy/client.go:
##########
@@ -1348,38 +1355,83 @@ func (c *Client) reconnect(ctx context.Context) {
                c.streamsMu.Unlock()
        }
 
+       // Each stream (re)start below can fail transiently when the new proxy 
pod is not yet accepting
+       // RPCs. reconnect() has already torn down the heartbeat ticker and all 
stream receive-loops -
+       // the only mechanisms that would otherwise re-trigger a reconnect - so 
returning here without
+       // rescheduling leaves the agent permanently disconnected 
(agents_online drops to 0 until a
+       // manual pod restart). Always schedule another attempt on failure.
        if regErr := c.StartRegistrationStream(ctx); regErr != nil {
-               c.logger.Error().Err(regErr).Msg("Failed to restart 
registration stream")
+               c.logger.Error().Err(regErr).Msg("Failed to restart 
registration stream; will retry")
+               c.scheduleReconnect(ctx)
                return
        }
 
        if metricsErr := c.StartMetricsStream(ctx); metricsErr != nil {
-               c.logger.Error().Err(metricsErr).Msg("Failed to restart metrics 
stream")
+               c.logger.Error().Err(metricsErr).Msg("Failed to restart metrics 
stream; will retry")
+               c.scheduleReconnect(ctx)
                return
        }
 
        if clusterStateErr := c.StartClusterStateStream(ctx); clusterStateErr 
!= nil {
-               c.logger.Error().Err(clusterStateErr).Msg("Failed to restart 
cluster state stream")
+               c.logger.Error().Err(clusterStateErr).Msg("Failed to restart 
cluster state stream; will retry")
+               c.scheduleReconnect(ctx)
                return
        }
 
        if c.lifecycleCollector != nil {
                if lifecycleErr := c.StartLifecycleStream(ctx); lifecycleErr != 
nil {
-                       c.logger.Error().Err(lifecycleErr).Msg("Failed to 
restart lifecycle stream")
+                       c.logger.Error().Err(lifecycleErr).Msg("Failed to 
restart lifecycle stream; will retry")
+                       c.scheduleReconnect(ctx)
                        return
                }
        }
 
        if c.collectionLister != nil {
                if crashErr := c.StartCrashStream(ctx); crashErr != nil {
-                       c.logger.Error().Err(crashErr).Msg("Failed to restart 
crash diagnostics stream")
+                       c.logger.Error().Err(crashErr).Msg("Failed to restart 
crash diagnostics stream; will retry")
+                       c.scheduleReconnect(ctx)
                        return
                }
        }
 
        c.logger.Info().Msg("Successfully reconnected to Proxy")
 }
 
+// scheduleReconnect arms a delayed reconnect attempt after a transient 
failure during reconnect
+// (e.g. the proxy pod not yet ready), so the agent keeps retrying instead of 
stalling forever.
+// reconnect() is single-flight and re-checks ctx and c.disconnected, so a 
timer that fires after
+// shutdown is a harmless no-op. Each failed reconnect arms exactly one timer, 
so retries proceed at
+// roughly one per interval rather than in a tight loop.
+func (c *Client) scheduleReconnect(ctx context.Context) {
+       c.streamsMu.Lock()
+       disconnected := c.disconnected
+       interval := c.reconnectInterval
+       c.streamsMu.Unlock()
+
+       if disconnected {
+               return
+       }
+       if interval <= 0 {
+               interval = defaultReconnectRetryInterval
+       }
+
+       select {
+       case <-ctx.Done():
+               return
+       default:
+       }
+
+       reconnectFn := c.reconnect
+       if c.reconnectFn != nil {
+               reconnectFn = c.reconnectFn
+       }
+
+       c.logger.Info().Dur("retry_in", interval).Msg("Scheduling proxy 
reconnect retry")
+       time.AfterFunc(interval, func() {
+               reconnectFn(ctx)
+       })

Review Comment:
   scheduleReconnect uses time.AfterFunc to invoke reconnectFn directly, which 
bypasses the usual recovered goroutine launcher used elsewhere in this client 
(run.Go) for reconnection work. If reconnect panics, it would crash the process 
without generating the expected panic diagnostics/recovery logs. Consider 
launching the reconnect attempt via run.Go from the timer callback for 
consistency and safety.



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