package controlplane import ( "context" "errors" ) var ErrSnapshotStreamClosed = errors.New("worker snapshot stream closed") type SessionRunner struct { reporter *RuntimeReporter watcher *SnapshotWatcher } func NewSessionRunner(reporter *RuntimeReporter, watcher *SnapshotWatcher) (*SessionRunner, error) { if reporter == nil || watcher == nil { return nil, ErrInvalidOptions } return &SessionRunner{reporter: reporter, watcher: watcher}, nil } // Run registers exactly once, then runs snapshot intake and Runtime reporting // against that session. A stream ending without context cancellation is a // failure so the owning process can apply its reconnect policy. func (runner *SessionRunner) Run(ctx context.Context) error { if runner == nil || ctx == nil { return ErrInvalidOptions } registration, err := runner.reporter.Register(ctx) if err != nil { return err } groupCtx, cancel := context.WithCancel(ctx) defer cancel() results := make(chan error, 2) go func() { results <- runner.watcher.Watch(groupCtx, registration.SessionID) }() go func() { results <- runner.reporter.RunRegistered(groupCtx) }() first := <-results cancel() second := <-results if ctx.Err() != nil { return ctx.Err() } if first == nil { return ErrSnapshotStreamClosed } if errors.Is(first, context.Canceled) && second != nil { return second } return first }