github.com/ashishbhate/mattermost-server@v5.11.1+incompatible/jobs/schedulers.go (about) 1 // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package jobs 5 6 import ( 7 "fmt" 8 "sync" 9 "time" 10 11 "github.com/mattermost/mattermost-server/mlog" 12 "github.com/mattermost/mattermost-server/model" 13 ) 14 15 type Schedulers struct { 16 stop chan bool 17 stopped chan bool 18 configChanged chan *model.Config 19 clusterLeaderChanged chan bool 20 listenerId string 21 startOnce sync.Once 22 jobs *JobServer 23 24 schedulers []model.Scheduler 25 nextRunTimes []*time.Time 26 } 27 28 func (srv *JobServer) InitSchedulers() *Schedulers { 29 mlog.Debug("Initialising schedulers.") 30 31 schedulers := &Schedulers{ 32 stop: make(chan bool), 33 stopped: make(chan bool), 34 configChanged: make(chan *model.Config), 35 clusterLeaderChanged: make(chan bool), 36 jobs: srv, 37 } 38 39 if srv.DataRetentionJob != nil { 40 schedulers.schedulers = append(schedulers.schedulers, srv.DataRetentionJob.MakeScheduler()) 41 } 42 43 if srv.MessageExportJob != nil { 44 schedulers.schedulers = append(schedulers.schedulers, srv.MessageExportJob.MakeScheduler()) 45 } 46 47 if elasticsearchAggregatorInterface := srv.ElasticsearchAggregator; elasticsearchAggregatorInterface != nil { 48 schedulers.schedulers = append(schedulers.schedulers, elasticsearchAggregatorInterface.MakeScheduler()) 49 } 50 51 if ldapSyncInterface := srv.LdapSync; ldapSyncInterface != nil { 52 schedulers.schedulers = append(schedulers.schedulers, ldapSyncInterface.MakeScheduler()) 53 } 54 55 if migrationsInterface := srv.Migrations; migrationsInterface != nil { 56 schedulers.schedulers = append(schedulers.schedulers, migrationsInterface.MakeScheduler()) 57 } 58 59 if pluginsInterface := srv.Plugins; pluginsInterface != nil { 60 schedulers.schedulers = append(schedulers.schedulers, pluginsInterface.MakeScheduler()) 61 } 62 63 schedulers.nextRunTimes = make([]*time.Time, len(schedulers.schedulers)) 64 return schedulers 65 } 66 67 func (schedulers *Schedulers) Start() *Schedulers { 68 schedulers.listenerId = schedulers.jobs.ConfigService.AddConfigListener(schedulers.handleConfigChange) 69 70 go func() { 71 schedulers.startOnce.Do(func() { 72 mlog.Info("Starting schedulers.") 73 74 defer func() { 75 mlog.Info("Schedulers stopped.") 76 close(schedulers.stopped) 77 }() 78 79 now := time.Now() 80 for idx, scheduler := range schedulers.schedulers { 81 if !scheduler.Enabled(schedulers.jobs.Config()) { 82 schedulers.nextRunTimes[idx] = nil 83 } else { 84 schedulers.setNextRunTime(schedulers.jobs.Config(), idx, now, false) 85 } 86 } 87 88 for { 89 select { 90 case <-schedulers.stop: 91 mlog.Debug("Schedulers received stop signal.") 92 return 93 case now = <-time.After(1 * time.Minute): 94 cfg := schedulers.jobs.Config() 95 96 for idx, nextTime := range schedulers.nextRunTimes { 97 if nextTime == nil { 98 continue 99 } 100 101 if time.Now().After(*nextTime) { 102 scheduler := schedulers.schedulers[idx] 103 if scheduler != nil { 104 if scheduler.Enabled(cfg) { 105 if _, err := schedulers.scheduleJob(cfg, scheduler); err != nil { 106 mlog.Warn(fmt.Sprintf("Failed to schedule job with scheduler: %v", scheduler.Name())) 107 mlog.Error(fmt.Sprint(err)) 108 } else { 109 schedulers.setNextRunTime(cfg, idx, now, true) 110 } 111 } 112 } 113 } 114 } 115 case newCfg := <-schedulers.configChanged: 116 for idx, scheduler := range schedulers.schedulers { 117 if !scheduler.Enabled(newCfg) { 118 schedulers.nextRunTimes[idx] = nil 119 } else { 120 schedulers.setNextRunTime(newCfg, idx, now, false) 121 } 122 } 123 case isLeader := <-schedulers.clusterLeaderChanged: 124 for idx := range schedulers.schedulers { 125 if !isLeader { 126 schedulers.nextRunTimes[idx] = nil 127 } else { 128 schedulers.setNextRunTime(schedulers.jobs.Config(), idx, now, false) 129 } 130 } 131 } 132 } 133 }) 134 }() 135 136 return schedulers 137 } 138 139 func (schedulers *Schedulers) Stop() *Schedulers { 140 mlog.Info("Stopping schedulers.") 141 close(schedulers.stop) 142 <-schedulers.stopped 143 return schedulers 144 } 145 146 func (schedulers *Schedulers) setNextRunTime(cfg *model.Config, idx int, now time.Time, pendingJobs bool) { 147 scheduler := schedulers.schedulers[idx] 148 149 if !pendingJobs { 150 if pj, err := schedulers.jobs.CheckForPendingJobsByType(scheduler.JobType()); err != nil { 151 mlog.Error("Failed to set next job run time: " + err.Error()) 152 schedulers.nextRunTimes[idx] = nil 153 return 154 } else { 155 pendingJobs = pj 156 } 157 } 158 159 lastSuccessfulJob, err := schedulers.jobs.GetLastSuccessfulJobByType(scheduler.JobType()) 160 if err != nil { 161 mlog.Error("Failed to set next job run time: " + err.Error()) 162 schedulers.nextRunTimes[idx] = nil 163 return 164 } 165 166 schedulers.nextRunTimes[idx] = scheduler.NextScheduleTime(cfg, now, pendingJobs, lastSuccessfulJob) 167 mlog.Debug(fmt.Sprintf("Next run time for scheduler %v: %v", scheduler.Name(), schedulers.nextRunTimes[idx])) 168 } 169 170 func (schedulers *Schedulers) scheduleJob(cfg *model.Config, scheduler model.Scheduler) (*model.Job, *model.AppError) { 171 pendingJobs, err := schedulers.jobs.CheckForPendingJobsByType(scheduler.JobType()) 172 if err != nil { 173 return nil, err 174 } 175 176 lastSuccessfulJob, err2 := schedulers.jobs.GetLastSuccessfulJobByType(scheduler.JobType()) 177 if err2 != nil { 178 return nil, err 179 } 180 181 return scheduler.ScheduleJob(cfg, pendingJobs, lastSuccessfulJob) 182 } 183 184 func (schedulers *Schedulers) handleConfigChange(oldConfig *model.Config, newConfig *model.Config) { 185 mlog.Debug("Schedulers received config change.") 186 schedulers.configChanged <- newConfig 187 } 188 189 func (schedulers *Schedulers) HandleClusterLeaderChange(isLeader bool) { 190 select { 191 case schedulers.clusterLeaderChanged <- isLeader: 192 default: 193 mlog.Debug("Did not send cluster leader change message to schedulers as no schedulers listening to notification channel.") 194 } 195 }