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  }