github.com/adacta-ru/mattermost-server@v5.11.1+incompatible/migrations/scheduler.go (about)

     1  // Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package migrations
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/mattermost/mattermost-server/app"
    10  	"github.com/mattermost/mattermost-server/mlog"
    11  	"github.com/mattermost/mattermost-server/model"
    12  	"github.com/mattermost/mattermost-server/store"
    13  )
    14  
    15  const (
    16  	MIGRATION_JOB_WEDGED_TIMEOUT_MILLISECONDS = 3600000 // 1 hour
    17  )
    18  
    19  type Scheduler struct {
    20  	App                    *app.App
    21  	allMigrationsCompleted bool
    22  }
    23  
    24  func (m *MigrationsJobInterfaceImpl) MakeScheduler() model.Scheduler {
    25  	return &Scheduler{m.App, false}
    26  }
    27  
    28  func (scheduler *Scheduler) Name() string {
    29  	return "MigrationsScheduler"
    30  }
    31  
    32  func (scheduler *Scheduler) JobType() string {
    33  	return model.JOB_TYPE_MIGRATIONS
    34  }
    35  
    36  func (scheduler *Scheduler) Enabled(cfg *model.Config) bool {
    37  	return true
    38  }
    39  
    40  func (scheduler *Scheduler) NextScheduleTime(cfg *model.Config, now time.Time, pendingJobs bool, lastSuccessfulJob *model.Job) *time.Time {
    41  	if scheduler.allMigrationsCompleted {
    42  		return nil
    43  	}
    44  
    45  	nextTime := time.Now().Add(60 * time.Second)
    46  	return &nextTime
    47  }
    48  
    49  func (scheduler *Scheduler) ScheduleJob(cfg *model.Config, pendingJobs bool, lastSuccessfulJob *model.Job) (*model.Job, *model.AppError) {
    50  	mlog.Debug("Scheduling Job", mlog.String("scheduler", scheduler.Name()))
    51  
    52  	// Work through the list of migrations in order. Schedule the first one that isn't done (assuming it isn't in progress already).
    53  	for _, key := range MakeMigrationsList() {
    54  		state, job, err := GetMigrationState(key, scheduler.App.Srv.Store)
    55  		if err != nil {
    56  			mlog.Error("Failed to determine status of migration: ", mlog.String("scheduler", scheduler.Name()), mlog.String("migration_key", key), mlog.String("error", err.Error()))
    57  			return nil, nil
    58  		}
    59  
    60  		if state == MIGRATION_STATE_IN_PROGRESS {
    61  			// Check the migration job isn't wedged.
    62  			if job != nil && job.LastActivityAt < model.GetMillis()-MIGRATION_JOB_WEDGED_TIMEOUT_MILLISECONDS && job.CreateAt < model.GetMillis()-MIGRATION_JOB_WEDGED_TIMEOUT_MILLISECONDS {
    63  				mlog.Warn("Job appears to be wedged. Rescheduling another instance.", mlog.String("scheduler", scheduler.Name()), mlog.String("wedged_job_id", job.Id), mlog.String("migration_key", key))
    64  				if err := scheduler.App.Srv.Jobs.SetJobError(job, nil); err != nil {
    65  					mlog.Error("Worker: Failed to set job error", mlog.String("scheduler", scheduler.Name()), mlog.String("job_id", job.Id), mlog.String("error", err.Error()))
    66  				}
    67  				return scheduler.createJob(key, job, scheduler.App.Srv.Store)
    68  			}
    69  
    70  			return nil, nil
    71  		}
    72  
    73  		if state == MIGRATION_STATE_COMPLETED {
    74  			// This migration is done. Continue to check the next.
    75  			continue
    76  		}
    77  
    78  		if state == MIGRATION_STATE_UNSCHEDULED {
    79  			mlog.Debug("Scheduling a new job for migration.", mlog.String("scheduler", scheduler.Name()), mlog.String("migration_key", key))
    80  			return scheduler.createJob(key, job, scheduler.App.Srv.Store)
    81  		}
    82  
    83  		mlog.Error("Unknown migration state. Not doing anything.", mlog.String("migration_state", state))
    84  		return nil, nil
    85  	}
    86  
    87  	// If we reached here, then there aren't any migrations left to run.
    88  	scheduler.allMigrationsCompleted = true
    89  	mlog.Debug("All migrations are complete.", mlog.String("scheduler", scheduler.Name()))
    90  
    91  	return nil, nil
    92  }
    93  
    94  func (scheduler *Scheduler) createJob(migrationKey string, lastJob *model.Job, store store.Store) (*model.Job, *model.AppError) {
    95  	var lastDone string
    96  	if lastJob != nil {
    97  		lastDone = lastJob.Data[JOB_DATA_KEY_MIGRATION_LAST_DONE]
    98  	}
    99  
   100  	data := map[string]string{
   101  		JOB_DATA_KEY_MIGRATION:           migrationKey,
   102  		JOB_DATA_KEY_MIGRATION_LAST_DONE: lastDone,
   103  	}
   104  
   105  	if job, err := scheduler.App.Srv.Jobs.CreateJob(model.JOB_TYPE_MIGRATIONS, data); err != nil {
   106  		return nil, err
   107  	} else {
   108  		return job, nil
   109  	}
   110  }