Run 阻塞运行 agent,直到 ctx 取消。期间任何错误(连接失败、stream 出错、 Recv EOF 等)都会触发指数退避重连。
(ctx context.Context, cfg Config)
| 114 | // Run 阻塞运行 agent,直到 ctx 取消。期间任何错误(连接失败、stream 出错、 |
| 115 | // Recv EOF 等)都会触发指数退避重连。 |
| 116 | func Run(ctx context.Context, cfg Config) error { |
| 117 | if cfg.Dispatcher == nil { |
| 118 | return errors.New("nodeagent: Config.Dispatcher is required") |
| 119 | } |
| 120 | if cfg.HelloProvider == nil { |
| 121 | return errors.New("nodeagent: Config.HelloProvider is required") |
| 122 | } |
| 123 | if cfg.ServerAddr == "" && cfg.Dialer == nil { |
| 124 | return errors.New("nodeagent: Config.ServerAddr or Config.Dialer is required") |
| 125 | } |
| 126 | if cfg.Logger == nil { |
| 127 | cfg.Logger = slog.Default() |
| 128 | } |
| 129 | if len(cfg.ReconnectBackoff) == 0 { |
| 130 | cfg.ReconnectBackoff = []time.Duration{2 * time.Second, 5 * time.Second, 15 * time.Second, 60 * time.Second} |
| 131 | } |
| 132 | if cfg.KeepaliveTime == 0 { |
| 133 | cfg.KeepaliveTime = 30 * time.Second |
| 134 | } |
| 135 | if cfg.KeepaliveTimeout == 0 { |
| 136 | cfg.KeepaliveTimeout = 10 * time.Second |
| 137 | } |
| 138 | |
| 139 | // 默认 Dialer:从 Cert/Key/CA 加载 mTLS,按 ServerAddr 建立 gRPC 连接。 |
| 140 | if cfg.Dialer == nil { |
| 141 | creds, err := loadTLSCreds(cfg) |
| 142 | if err != nil { |
| 143 | return fmt.Errorf("nodeagent: load TLS: %w", err) |
| 144 | } |
| 145 | cfg.Dialer = func(_ context.Context) (*grpc.ClientConn, error) { |
| 146 | return grpc.NewClient(cfg.ServerAddr, |
| 147 | grpc.WithTransportCredentials(creds), |
| 148 | keepaliveParams(cfg), |
| 149 | ) |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | attempts := 0 |
| 154 | for { |
| 155 | err := runSession(ctx, cfg) |
| 156 | if ctx.Err() != nil { |
| 157 | return ctx.Err() |
| 158 | } |
| 159 | // 选取等待时长:min(attempts, len-1)。 |
| 160 | idx := attempts |
| 161 | if idx >= len(cfg.ReconnectBackoff) { |
| 162 | idx = len(cfg.ReconnectBackoff) - 1 |
| 163 | } |
| 164 | wait := cfg.ReconnectBackoff[idx] |
| 165 | cfg.Logger.Warn("nodeagent: session ended, reconnecting", |
| 166 | "node_id", cfg.NodeID, "wait", wait, "attempt", attempts, "err", err) |
| 167 | select { |
| 168 | case <-time.After(wait): |
| 169 | attempts++ |
| 170 | case <-ctx.Done(): |
| 171 | return ctx.Err() |
| 172 | } |
| 173 | } |