github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/migrations/scheduler.go (about)

     1  // Copyright (c) 2015-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/masterhung0112/hk_server/v5/app"
    10  	"github.com/masterhung0112/hk_server/v5/model"
    11  	"github.com/masterhung0112/hk_server/v5/shared/mlog"
    12  )
    13  
    14  const (
    15  	MigrationJobWedgedTimeoutMilliseconds = 3600000 // 1 hour
    16  )
    17  
    18  type Scheduler struct {
    19  	srv                    *app.Server
    20  	allMigrationsCompleted bool
    21  }
    22  
    23  func (m *MigrationsJobInterfaceImpl) MakeScheduler() model.Scheduler {
    24  	return &Scheduler{m.srv, false}
    25  }
    26  
    27  func (scheduler *Scheduler) Name() string {
    28  	return "MigrationsScheduler"
    29  }
    30  
    31  func (scheduler *Scheduler) JobType() string {
    32  	return model.JOB_TYPE_MIGRATIONS
    33  }
    34  
    35  func (scheduler *Scheduler) Enabled(_ *model.Config) bool {
    36  	return true
    37  }
    38  
    39  //nolint:unparam
    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  //nolint:unparam
    50  func (scheduler *Scheduler) ScheduleJob(cfg *model.Config, pendingJobs bool, lastSuccessfulJob *model.Job) (*model.Job, *model.AppError) {
    51  	mlog.Debug("Scheduling Job", mlog.String("scheduler", scheduler.Name()))
    52  
    53  	// Work through the list of migrations in order. Schedule the first one that isn't done (assuming it isn't in progress already).
    54  	for _, key := range MakeMigrationsList() {
    55  		state, job, err := GetMigrationState(key, scheduler.srv.Store)
    56  		if err != nil {
    57  			mlog.Error("Failed to determine status of migration: ", mlog.String("scheduler", scheduler.Name()), mlog.String("migration_key", key), mlog.String("error", err.Error()))
    58  			return nil, nil
    59  		}
    60  
    61  		if state == MigrationStateInProgress {
    62  			// Check the migration job isn't wedged.
    63  			if job != nil && job.LastActivityAt < model.GetMillis()-MigrationJobWedgedTimeoutMilliseconds && job.CreateAt < model.GetMillis()-MigrationJobWedgedTimeoutMilliseconds {
    64  				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))
    65  				if err := scheduler.srv.Jobs.SetJobError(job, nil); err != nil {
    66  					mlog.Error("Worker: Failed to set job error", mlog.String("scheduler", scheduler.Name()), mlog.String("job_id", job.Id), mlog.String("error", err.Error()))
    67  				}
    68  				return scheduler.createJob(key, job)
    69  			}
    70  
    71  			return nil, nil
    72  		}
    73  
    74  		if state == MigrationStateCompleted {
    75  			// This migration is done. Continue to check the next.
    76  			continue
    77  		}
    78  
    79  		if state == MigrationStateUnscheduled {
    80  			mlog.Debug("Scheduling a new job for migration.", mlog.String("scheduler", scheduler.Name()), mlog.String("migration_key", key))
    81  			return scheduler.createJob(key, job)
    82  		}
    83  
    84  		mlog.Error("Unknown migration state. Not doing anything.", mlog.String("migration_state", state))
    85  		return nil, nil
    86  	}
    87  
    88  	// If we reached here, then there aren't any migrations left to run.
    89  	scheduler.allMigrationsCompleted = true
    90  	mlog.Debug("All migrations are complete.", mlog.String("scheduler", scheduler.Name()))
    91  
    92  	return nil, nil
    93  }
    94  
    95  func (scheduler *Scheduler) createJob(migrationKey string, lastJob *model.Job) (*model.Job, *model.AppError) {
    96  	var lastDone string
    97  	if lastJob != nil {
    98  		lastDone = lastJob.Data[JobDataKeyMigration_LAST_DONE]
    99  	}
   100  
   101  	data := map[string]string{
   102  		JobDataKeyMigration:           migrationKey,
   103  		JobDataKeyMigration_LAST_DONE: lastDone,
   104  	}
   105  
   106  	job, err := scheduler.srv.Jobs.CreateJob(model.JOB_TYPE_MIGRATIONS, data)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  	return job, nil
   111  }