package main import "time" type Job interface { Schedule() Stop() Run() } type jobIdentifier int const ( JobIdCloseDecisions jobIdentifier = iota ) var rescheduleChannel = make(chan jobIdentifier, 1) func JobScheduler(quitChannel chan int) { var jobs = map[jobIdentifier]Job{ JobIdCloseDecisions: NewCloseDecisionsJob(), } logger.Println("INFO started job scheduler") for { select { case jobId := <-rescheduleChannel: job := jobs[jobId] logger.Println("INFO reschedule job", job) job.Schedule() case <-quitChannel: for _, job := range jobs { job.Stop() } logger.Println("INFO stop job scheduler") return } } } type CloseDecisionsJob struct { timer *time.Timer } func NewCloseDecisionsJob() *CloseDecisionsJob { job := &CloseDecisionsJob{} job.Schedule() return job } func (j *CloseDecisionsJob) Schedule() { var nextDue *time.Time nextDue, err := GetNextPendingDecisionDue() if err != nil { logger.Fatal("ERROR Could not get next pending due date") if j.timer != nil { j.timer.Stop() j.timer = nil } return } if nextDue == nil { if j.timer != nil { j.timer.Stop() j.timer = nil } } else { logger.Println("INFO scheduling CloseDecisionsJob for", nextDue) when := nextDue.Sub(time.Now()) if j.timer != nil { j.timer.Reset(when) } else { j.timer = time.AfterFunc(when, j.Run) } } } func (j *CloseDecisionsJob) Stop() { if j.timer != nil { j.timer.Stop() } } func (j *CloseDecisionsJob) Run() { logger.Println("INFO running CloseDecisionsJob") err := CloseDecisions() if err != nil { logger.Println("ERROR closing decisions", err) } rescheduleChannel <- JobIdCloseDecisions } func (j *CloseDecisionsJob) String() string { return "CloseDecisionsJob" }