github.com/polarismesh/polaris@v1.17.8/admin/job/job.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package job
    19  
    20  import (
    21  	"context"
    22  	"fmt"
    23  	"os"
    24  	"time"
    25  
    26  	"github.com/polarismesh/polaris/cache"
    27  	commonlog "github.com/polarismesh/polaris/common/log"
    28  	"github.com/polarismesh/polaris/common/utils"
    29  	"github.com/polarismesh/polaris/service"
    30  	"github.com/polarismesh/polaris/store"
    31  )
    32  
    33  var log = commonlog.GetScopeOrDefaultByName(commonlog.DefaultLoggerName)
    34  
    35  // MaintainJobs
    36  type MaintainJobs struct {
    37  	jobs        map[string]maintainJob
    38  	startedJobs map[string]maintainJob
    39  	storage     store.Store
    40  	cancel      context.CancelFunc
    41  }
    42  
    43  // NewMaintainJobs
    44  func NewMaintainJobs(namingServer service.DiscoverServer, cacheMgn *cache.CacheManager,
    45  	storage store.Store) *MaintainJobs {
    46  	return &MaintainJobs{
    47  		jobs: map[string]maintainJob{
    48  			"DeleteUnHealthyInstance": &deleteUnHealthyInstanceJob{
    49  				namingServer: namingServer, storage: storage},
    50  			"DeleteEmptyService": &deleteEmptyServiceJob{
    51  				namingServer: namingServer, cacheMgn: cacheMgn, storage: storage},
    52  			"CleanDeletedInstances": &cleanDeletedInstancesJob{
    53  				storage: storage},
    54  			"CleanDeletedClients": &cleanDeletedClientsJob{
    55  				storage: storage},
    56  			"CleanConfigReleaseHistory": &cleanConfigFileHistoryJob{
    57  				storage: storage},
    58  		},
    59  		startedJobs: map[string]maintainJob{},
    60  		storage:     storage,
    61  	}
    62  }
    63  
    64  // StartMaintainJobs
    65  func (mj *MaintainJobs) StartMaintianJobs(configs []JobConfig) error {
    66  	ctx, cancel := context.WithCancel(context.Background())
    67  	mj.cancel = cancel
    68  	for _, cfg := range configs {
    69  		if !cfg.Enable {
    70  			log.Infof("[Maintain][Job] job (%s) not enable", cfg.Name)
    71  			continue
    72  		}
    73  		jobName := parseJobName(cfg.Name)
    74  		job, ok := mj.findAdminJob(jobName)
    75  		if !ok {
    76  			return fmt.Errorf("[Maintain][Job] job (%s) not exist", jobName)
    77  		}
    78  		if _, ok := mj.startedJobs[jobName]; ok {
    79  			return fmt.Errorf("[Maintain][Job] job (%s) duplicated", jobName)
    80  		}
    81  		if err := job.init(cfg.Option); err != nil {
    82  			log.Errorf("[Maintain][Job] job (%s) fail to init, err: %v", jobName, err)
    83  			return fmt.Errorf("[Maintain][Job] job (%s) fail to init", jobName)
    84  		}
    85  		if err := mj.storage.StartLeaderElection(store.ElectionKeyMaintainJobPrefix + jobName); err != nil {
    86  			log.Errorf("[Maintain][Job][%s] start leader election err: %v", jobName, err)
    87  			return err
    88  		}
    89  		runAdminJob(ctx, jobName, job.interval(), job, mj.storage)
    90  		mj.startedJobs[jobName] = job
    91  	}
    92  	return nil
    93  }
    94  
    95  func parseJobName(name string) string {
    96  	// 兼容老配置
    97  	if name == "DeleteEmptyAutoCreatedService" {
    98  		name = "DeleteEmptyService"
    99  	}
   100  	return name
   101  }
   102  
   103  func (mj *MaintainJobs) findAdminJob(name string) (maintainJob, bool) {
   104  	job, ok := mj.jobs[name]
   105  	if !ok {
   106  		return nil, false
   107  	}
   108  
   109  	return job, true
   110  }
   111  
   112  // StopMaintainJobs
   113  func (mj *MaintainJobs) StopMaintainJobs() {
   114  	if mj.cancel != nil {
   115  		mj.cancel()
   116  	}
   117  	mj.startedJobs = map[string]maintainJob{}
   118  }
   119  
   120  func runAdminJob(ctx context.Context, name string, interval time.Duration, job maintainJob, storage store.Store) {
   121  	f := func() {
   122  		if !storage.IsLeader(store.ElectionKeyMaintainJobPrefix + name) {
   123  			log.Infof("[Maintain][Job][%s] I am follower", name)
   124  			job.clear()
   125  			return
   126  		}
   127  		log.Infof("[Maintain][Job][%s] I am leader, job start", name)
   128  		job.execute()
   129  		log.Infof("[Maintain][Job][%s] I am leader, job end", name)
   130  	}
   131  
   132  	ticker := time.NewTicker(interval)
   133  	go func(ctx context.Context) {
   134  		for {
   135  			select {
   136  			case <-ctx.Done():
   137  				return
   138  			case <-ticker.C:
   139  				f()
   140  			}
   141  		}
   142  	}(ctx)
   143  }
   144  
   145  type maintainJob interface {
   146  	init(cfg map[string]interface{}) error
   147  	execute()
   148  	clear()
   149  	interval() time.Duration
   150  }
   151  
   152  func getMasterAccountToken(storage store.Store) (string, error) {
   153  	mainUser := os.Getenv("POLARIS_MAIN_USER")
   154  	if mainUser == "" {
   155  		mainUser = "polaris"
   156  	}
   157  	user, err := storage.GetUserByName(mainUser, "")
   158  	if err != nil {
   159  		return "", err
   160  	}
   161  	if user == nil {
   162  		return "", fmt.Errorf("polaris main user: %s not found", mainUser)
   163  	}
   164  	return user.Token, nil
   165  }
   166  
   167  func buildContext(storage store.Store) (context.Context, error) {
   168  	token, err := getMasterAccountToken(storage)
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  	ctx := context.Background()
   173  	ctx = context.WithValue(ctx, utils.ContextAuthTokenKey, token)
   174  	ctx = context.WithValue(ctx, utils.ContextOperator, "maintain-job")
   175  	return ctx, nil
   176  }