StartWatcher creates and starts a K8s watcher in background from interactive mode.
(ctx context.Context, cfg k8s.WatchConfig)
| 18 | |
| 19 | // StartWatcher creates and starts a K8s watcher in background from interactive mode. |
| 20 | func (cli *ChatCLI) StartWatcher(ctx context.Context, cfg k8s.WatchConfig) error { |
| 21 | if cli.isWatching { |
| 22 | return fmt.Errorf("watcher already running, use /watch stop first") |
| 23 | } |
| 24 | |
| 25 | watcher, err := k8s.NewResourceWatcher(cfg, cli.logger) |
| 26 | if err != nil { |
| 27 | return fmt.Errorf("failed to create K8s watcher: %w", err) |
| 28 | } |
| 29 | |
| 30 | store := watcher.GetStore() |
| 31 | summarizer := k8s.NewSummarizer(store) |
| 32 | |
| 33 | // The watcher runs in a detached background goroutine that must outlive |
| 34 | // the /watch start command; its lifetime is governed by cli.watcherCancel |
| 35 | // (invoked by StopWatcher), not by the per-command ctx. WithoutCancel |
| 36 | // keeps inherited values while decoupling from the command's cancellation. |
| 37 | watchCtx, watchCancel := context.WithCancel(context.WithoutCancel(ctx)) |
| 38 | cli.watcherCancel = watchCancel |
| 39 | |
| 40 | watcherReady := make(chan struct{}, 1) |
| 41 | go func() { |
| 42 | go func() { |
| 43 | ticker := time.NewTicker(500 * time.Millisecond) |
| 44 | defer ticker.Stop() |
| 45 | timeout := time.After(15 * time.Second) |
| 46 | for { |
| 47 | select { |
| 48 | case <-ticker.C: |
| 49 | if _, ok := store.LatestSnapshot(); ok { |
| 50 | watcherReady <- struct{}{} |
| 51 | return |
| 52 | } |
| 53 | case <-timeout: |
| 54 | watcherReady <- struct{}{} |
| 55 | return |
| 56 | } |
| 57 | } |
| 58 | }() |
| 59 | |
| 60 | if err := watcher.Start(watchCtx); err != nil && !errors.Is(err, context.Canceled) { |
| 61 | cli.logger.Error("K8s watcher stopped with error", zap.Error(err)) |
| 62 | } |
| 63 | }() |
| 64 | |
| 65 | // Wait for first collection |
| 66 | <-watcherReady |
| 67 | |
| 68 | cli.WatcherContextFunc = summarizer.GenerateContext |
| 69 | cli.SetWatching(true, summarizer.GenerateStatusSummary) |
| 70 | |
| 71 | if _, ok := store.LatestSnapshot(); ok { |
| 72 | cli.logger.Info("K8s watcher started with initial data", |
| 73 | zap.String("deployment", cfg.Deployment), |
| 74 | zap.String("namespace", cfg.Namespace)) |
| 75 | } |
| 76 | |
| 77 | return nil |
no test coverage detected