Ctrl K
ComunidadGuías…

utils/setup_gate.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package utils

import (
	"context"
	"sync"
)

// SetupGate is a recording's rule for its agent's lifetime around an
// interrupt: an interrupt (ctx done) while the agent is still being set up
// cancels the agent's lifetime (cancel) at once; once the agent is up (Up), an
// interrupt leaves it running, and the teardown stops it after the stop's
// drain has taken what it captured. The interrupt and Up are decided under one
// lock, so an interrupt that lands as the setup finishes either cancelled the
// setup, and Up says so, or cancels nothing. Decided by which of two ready
// channels a select took, an interrupt could cancel an agent that was already
// up, after the setup had returned, and the run went on with an agent that
// was stopping.
type SetupGate struct {
	mu     sync.Mutex
	up     bool
	cut    bool
	cancel context.CancelFunc
	// unwatch stops watching ctx once the agent is up, so a gate on a
	// long-lived context leaves nothing registered on it.
	unwatch func() bool
}

// NewSetupGate watches ctx for the interrupt, and calls cancel for it while
// the agent is being set up.
func NewSetupGate(ctx context.Context, cancel context.CancelFunc) *SetupGate {
	g := &SetupGate{cancel: cancel}
	g.unwatch = context.AfterFunc(ctx, func() {
		g.mu.Lock()
		defer g.mu.Unlock()
		if !g.up {
			g.cut = true
			g.cancel()
		}
	})
	return g
}

// Up says the agent is up: an interrupt from now on leaves it to the
// teardown. It reports false when an interrupt cancelled the setup first: the
// agent is stopping, and the run ends as an interrupted setup does.
func (g *SetupGate) Up() bool {
	g.mu.Lock()
	defer g.mu.Unlock()
	if g.cut {
		return false
	}
	g.up = true
	g.unwatch()
	return true
}