package services import ( "encoding/json" "fmt" "sync" "time" ) func NewService(msg json.RawMessage) (*Service, error) { var config struct { Name string `json:"name"` Interval int64 `json:"interval"` Type string `json:"type"` Config json.RawMessage `json:"config"` } err := json.Unmarshal(msg, &config) if err != nil { return nil, err } interval := time.Duration(config.Interval) * time.Second factory, found := Factories[config.Type] if !found { return nil, fmt.Errorf("no factory: %s", config.Type) } check, err := factory(config.Config) if err != nil { return nil, fmt.Errorf("failed to create check: %w", err) } service := &Service{ Name: config.Name, Interval: interval, Check: check, lastMutex: sync.Mutex{}, lastStatus: StatusUnknown, lastCheck: time.Unix(0, 0), } return service, nil } type Service struct { Name string Interval time.Duration Check Check lastMutex sync.Mutex lastStatus Status lastCheck time.Time } func (s *Service) Start(stop chan bool) { ticker := time.Tick(s.Interval) // Need to do instant check, ticker only sends the first tick after waiting for s.Interval s.check() for { select { case <-stop: return case <-ticker: s.check() } } } func (s *Service) check() { status := s.Check() s.lastMutex.Lock() defer s.lastMutex.Unlock() s.lastStatus = status s.lastCheck = time.Now().In(time.UTC) } func (s *Service) Status() (Status, time.Time) { s.lastMutex.Lock() defer s.lastMutex.Unlock() return s.lastStatus, s.lastCheck }