github.com/adacta-ru/mattermost-server/v5@v5.31.1/jobs/schedulers.go (about) 1 // Copyright (c) 2015-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/adacta-ru/mattermost-server/v5/mlog" 12 "github.com/adacta-ru/mattermost-server/v5/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 isLeader bool 24 25 schedulers []model.Scheduler 26 nextRunTimes []*time.Time 27 } 28 29 func (srv *JobServer) InitSchedulers() *Schedulers { 30 mlog.Debug("Initialising schedulers.") 31 32 schedulers := &Schedulers{ 33 stop: make(chan bool), 34 stopped: make(chan bool), 35 configChanged: make(chan *model.Config), 36 clusterLeaderChanged: make(chan bool), 37 jobs: srv, 38 isLeader: true, 39 } 40 41 if srv.DataRetentionJob != nil { 42 schedulers.schedulers = append(schedulers.schedulers, srv.DataRetentionJob.MakeScheduler()) 43 } 44 45 if srv.MessageExportJob != nil { 46 schedulers.schedulers = append(schedulers.schedulers, srv.MessageExportJob.MakeScheduler()) 47 } 48 49 if elasticsearchAggregatorInterface := srv.ElasticsearchAggregator; elasticsearchAggregatorInterface != nil { 50 schedulers.schedulers = append(schedulers.schedulers, elasticsearchAggregatorInterface.MakeScheduler()) 51 } 52 53 if ldapSyncInterface := srv.LdapSync; ldapSyncInterface != nil { 54 schedulers.schedulers = append(schedulers.schedulers, ldapSyncInterface.MakeScheduler()) 55 } 56 57 if migrationsInterface := srv.Migrations; migrationsInterface != nil { 58 schedulers.schedulers = append(schedulers.schedulers, migrationsInterface.MakeScheduler()) 59 } 60 61 if pluginsInterface := srv.Plugins; pluginsInterface != nil { 62 schedulers.schedulers = append(schedulers.schedulers, pluginsInterface.MakeScheduler()) 63 } 64 65 if expiryNotifyInterface := srv.ExpiryNotify; expiryNotifyInterface != nil { 66 schedulers.schedulers = append(schedulers.schedulers, expiryNotifyInterface.MakeScheduler()) 67 } 68 69 if activeUsersInterface := srv.ActiveUsers; activeUsersInterface != nil { 70 schedulers.schedulers = append(schedulers.schedulers, activeUsersInterface.MakeScheduler()) 71 } 72 if productNoticesInterface := srv.ProductNotices; productNoticesInterface != nil { 73 schedulers.schedulers = append(schedulers.schedulers, productNoticesInterface.MakeScheduler()) 74 } 75 76 if cloudInterface := srv.Cloud; cloudInterface != nil { 77 schedulers.schedulers = append(schedulers.schedulers, cloudInterface.MakeScheduler()) 78 } 79 80 schedulers.nextRunTimes = make([]*time.Time, len(schedulers.schedulers)) 81 return schedulers 82 } 83 84 func (schedulers *Schedulers) Start() *Schedulers { 85 schedulers.listenerId = schedulers.jobs.ConfigService.AddConfigListener(schedulers.handleConfigChange) 86 87 go func() { 88 schedulers.startOnce.Do(func() { 89 mlog.Info("Starting schedulers.") 90 91 defer func() { 92 mlog.Info("Schedulers stopped.") 93 close(schedulers.stopped) 94 }() 95 96 now := time.Now() 97 for idx, scheduler := range schedulers.schedulers { 98 if !scheduler.Enabled(schedulers.jobs.Config()) { 99 schedulers.nextRunTimes[idx] = nil 100 } else { 101 schedulers.setNextRunTime(schedulers.jobs.Config(), idx, now, false) 102 } 103 } 104 105 for { 106 timer := time.NewTimer(1 * time.Minute) 107 select { 108 case <-schedulers.stop: 109 mlog.Debug("Schedulers received stop signal.") 110 timer.Stop() 111 return 112 case now = <-timer.C: 113 cfg := schedulers.jobs.Config() 114 115 for idx, nextTime := range schedulers.nextRunTimes { 116 if nextTime == nil { 117 continue 118 } 119 120 if time.Now().After(*nextTime) { 121 scheduler := schedulers.schedulers[idx] 122 if scheduler != nil { 123 if schedulers.isLeader && scheduler.Enabled(cfg) { 124 if _, err := schedulers.scheduleJob(cfg, scheduler); err != nil { 125 mlog.Error("Failed to schedule job", mlog.String("scheduler", scheduler.Name()), mlog.Err(err)) 126 } else { 127 schedulers.setNextRunTime(cfg, idx, now, true) 128 } 129 } 130 } 131 } 132 } 133 case newCfg := <-schedulers.configChanged: 134 for idx, scheduler := range schedulers.schedulers { 135 if !schedulers.isLeader || !scheduler.Enabled(newCfg) { 136 schedulers.nextRunTimes[idx] = nil 137 } else { 138 schedulers.setNextRunTime(newCfg, idx, now, false) 139 } 140 } 141 case isLeader := <-schedulers.clusterLeaderChanged: 142 for idx := range schedulers.schedulers { 143 schedulers.isLeader = isLeader 144 if !isLeader { 145 schedulers.nextRunTimes[idx] = nil 146 } else { 147 schedulers.setNextRunTime(schedulers.jobs.Config(), idx, now, false) 148 } 149 } 150 } 151 timer.Stop() 152 } 153 }) 154 }() 155 156 return schedulers 157 } 158 159 func (schedulers *Schedulers) Stop() *Schedulers { 160 mlog.Info("Stopping schedulers.") 161 close(schedulers.stop) 162 <-schedulers.stopped 163 return schedulers 164 } 165 166 func (schedulers *Schedulers) setNextRunTime(cfg *model.Config, idx int, now time.Time, pendingJobs bool) { 167 scheduler := schedulers.schedulers[idx] 168 169 if !pendingJobs { 170 pj, err := schedulers.jobs.CheckForPendingJobsByType(scheduler.JobType()) 171 if err != nil { 172 mlog.Error("Failed to set next job run time", mlog.Err(err)) 173 schedulers.nextRunTimes[idx] = nil 174 return 175 } 176 pendingJobs = pj 177 } 178 179 lastSuccessfulJob, err := schedulers.jobs.GetLastSuccessfulJobByType(scheduler.JobType()) 180 if err != nil { 181 mlog.Error("Failed to set next job run time", mlog.Err(err)) 182 schedulers.nextRunTimes[idx] = nil 183 return 184 } 185 186 schedulers.nextRunTimes[idx] = scheduler.NextScheduleTime(cfg, now, pendingJobs, lastSuccessfulJob) 187 mlog.Debug("Next run time for scheduler", mlog.String("scheduler_name", scheduler.Name()), mlog.String("next_runtime", fmt.Sprintf("%v", schedulers.nextRunTimes[idx]))) 188 } 189 190 func (schedulers *Schedulers) scheduleJob(cfg *model.Config, scheduler model.Scheduler) (*model.Job, *model.AppError) { 191 pendingJobs, err := schedulers.jobs.CheckForPendingJobsByType(scheduler.JobType()) 192 if err != nil { 193 return nil, err 194 } 195 196 lastSuccessfulJob, err2 := schedulers.jobs.GetLastSuccessfulJobByType(scheduler.JobType()) 197 if err2 != nil { 198 return nil, err 199 } 200 201 return scheduler.ScheduleJob(cfg, pendingJobs, lastSuccessfulJob) 202 } 203 204 func (schedulers *Schedulers) handleConfigChange(oldConfig, newConfig *model.Config) { 205 mlog.Debug("Schedulers received config change.") 206 schedulers.configChanged <- newConfig 207 } 208 209 func (schedulers *Schedulers) HandleClusterLeaderChange(isLeader bool) { 210 select { 211 case schedulers.clusterLeaderChanged <- isLeader: 212 default: 213 mlog.Debug("Did not send cluster leader change message to schedulers as no schedulers listening to notification channel.") 214 } 215 }