package agent import ( "context" "time" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/logger" ) type Agent struct { controllers []Controller interval time.Duration } func (a *Agent) Run(ctx context.Context) error { ticker := time.NewTicker(a.interval) defer ticker.Stop() prevState := NewState() for { select { case <-ticker.C: newState, err := a.Reconcile(ctx, prevState) if err != nil { logger.Error(ctx, "could not reconcile node with desired state", logger.E(errors.WithStack(err))) continue } if newState != nil { prevState = newState } case <-ctx.Done(): return errors.WithStack(ctx.Err()) } } } func (a *Agent) Reconcile(ctx context.Context, state *State) (*State, error) { prevState := state for _, ctrl := range a.controllers { ctrlCtx := logger.With(ctx, logger.F("controller", ctrl.Name())) logger.Debug( ctrlCtx, "executing controller", logger.F("state", state), ) newState, err := ctrl.Reconcile(ctrlCtx, prevState) if err != nil { return nil, errors.WithStack(err) } logger.Debug(ctrlCtx, "new state", logger.F("newState", newState)) if newState != nil { prevState = newState } } return prevState, nil } func New(funcs ...OptionFunc) *Agent { opt := defaultOption() for _, fn := range funcs { fn(opt) } return &Agent{ controllers: opt.Controllers, interval: opt.Interval, } }