AFAIRE
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
scheduler/scheduler.go

153 lines
3.1 KiB

/*
------------------------------------------------------------------------------------------------------------------------
####### scheduler ####### Copyright (c) 2021-2022 losyme ########################################### MIT License #######
------------------------------------------------------------------------------------------------------------------------
*/
package scheduler
import (
"errors"
"fmt"
"time"
"forge.chapril.org/losyme/zombie"
"github.com/robfig/cron/v3"
)
type Scheduler struct {
config *Config
parser cron.Parser
handler *handler
zombie *zombie.Group
}
func New(c *Config) (*Scheduler, error) {
if c == nil {
return nil, errors.New("no configuration provided") ////////////////////////////////////////////////////////////
}
if err := c.validate(); err != nil {
return nil, err
}
cronLogger := newCronLogger(c.Logger)
parser := cron.NewParser(
cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor,
)
handler := &handler{
onMessage: c.OnMessage,
cron: cron.New(
cron.WithChain(
cron.Recover(cronLogger),
cron.SkipIfStillRunning(cronLogger),
),
cron.WithLogger(cronLogger),
cron.WithParser(parser),
),
}
scheduler := &Scheduler{
config: c,
parser: parser,
handler: handler,
}
return scheduler, nil
}
type Event struct {
Name string `cfg:"name"`
Disabled bool `cfg:"disabled"`
After time.Duration `cfg:"after"`
Repeat string `cfg:"repeat"`
Data interface{} `cfg:"data"`
}
func (s *Scheduler) AddEvent(e *Event) error {
if e == nil {
return errors.New("event cannot be nil") ///////////////////////////////////////////////////////////////////////
}
if e.Name == "" {
return errors.New("event name cannot be empty") ////////////////////////////////////////////////////////////////
}
// Pour le moment, on les élimine.
// Dans une prochaine version, on les prendra en compte pour pouvoir les activer en cours d'exécution.
if e.Disabled {
return nil
}
event := &event{
name: e.Name,
data: e.Data,
handler: s.handler,
}
eStarter := &eStarter{
event: event,
}
if e.After != 0 {
entryID, err := s.handler.cron.AddJob(fmt.Sprintf("@every %s", e.After.String()), eStarter)
if err != nil {
return err
}
eStarter.after = entryID
}
if e.Repeat == "" {
if e.After != 0 {
return nil
}
return errors.New("at least one of the fields After or Repeat must be initialized") ////////////////////////////
}
schedule, err := s.parser.Parse(e.Repeat)
if err != nil {
return err
}
if e.After == 0 {
_ = s.handler.cron.Schedule(schedule, event)
} else {
eStarter.repeat = schedule
}
return nil
}
func (s *Scheduler) Start() {
if s.zombie != nil {
return
}
s.zombie = zombie.Go(
1,
func(_ int) {
s.handler.cron.Run()
},
zombie.WithName("scheduler"),
zombie.WithLogger(s.config.Logger),
)
}
func (s *Scheduler) Stop() {
if s.zombie == nil {
return
}
<-s.handler.cron.Stop().Done()
s.zombie.Wait()
s.zombie = nil
}
/*
######################################################################################################## @(°_°)@ #######
*/