github.com/polarismesh/polaris@v1.17.8/service/healthcheck/leader.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 healthcheck 19 20 import ( 21 "context" 22 "time" 23 24 apimodel "github.com/polarismesh/specification/source/go/api/v1/model" 25 26 "github.com/polarismesh/polaris/common/model" 27 "github.com/polarismesh/polaris/plugin" 28 "github.com/polarismesh/polaris/store" 29 ) 30 31 // LeaderChangeEventHandler process the event when server act as leader 32 type LeaderChangeEventHandler struct { 33 cacheProvider *CacheProvider 34 ctx context.Context 35 cancel context.CancelFunc 36 minCheckInterval time.Duration 37 } 38 39 // newLeaderChangeEventHandler 40 func newLeaderChangeEventHandler(cacheProvider *CacheProvider, 41 minCheckInterval time.Duration) *LeaderChangeEventHandler { 42 43 return &LeaderChangeEventHandler{ 44 cacheProvider: cacheProvider, 45 minCheckInterval: minCheckInterval, 46 } 47 } 48 49 // PreProcess do preprocess logic for event 50 func (handler *LeaderChangeEventHandler) PreProcess(ctx context.Context, value any) any { 51 return value 52 } 53 54 // OnEvent event trigger 55 func (handler *LeaderChangeEventHandler) OnEvent(ctx context.Context, i interface{}) error { 56 e := i.(store.LeaderChangeEvent) 57 if e.Key != store.ElectionKeySelfServiceChecker { 58 return nil 59 } 60 61 if e.Leader { 62 handler.startCheckSelfServiceInstances() 63 } else { 64 handler.stopCheckSelfServiceInstances() 65 } 66 return nil 67 } 68 69 // startCheckSelfServiceInstances 70 func (handler *LeaderChangeEventHandler) startCheckSelfServiceInstances() { 71 if handler.ctx != nil { 72 log.Warn("[healthcheck] receive unexpected leader state event") 73 return 74 } 75 76 ctx, cancel := context.WithCancel(context.Background()) 77 handler.ctx = ctx 78 handler.cancel = cancel 79 go func() { 80 log.Info("[healthcheck] i am leader, start check health of selfService instances") 81 ticker := time.NewTicker(handler.minCheckInterval) 82 defer ticker.Stop() 83 for { 84 select { 85 case <-ticker.C: 86 handler.cacheProvider.selfServiceInstances.Range(func(instanceId string, value ItemWithChecker) { 87 handler.doCheckSelfServiceInstance(value.GetInstance()) 88 }) 89 case <-ctx.Done(): 90 log.Info("[healthcheck] stop check health of selfService instances") 91 return 92 } 93 } 94 }() 95 } 96 97 // startCheckSelfServiceInstances 98 func (handler *LeaderChangeEventHandler) stopCheckSelfServiceInstances() { 99 if handler.ctx == nil { 100 return 101 } 102 handler.cancel() 103 handler.ctx = nil 104 handler.cancel = nil 105 } 106 107 // startCheckSelfServiceInstances 108 func (handler *LeaderChangeEventHandler) doCheckSelfServiceInstance(cachedInstance *model.Instance) { 109 hcEnable, checker := handler.cacheProvider.isHealthCheckEnable(cachedInstance.Proto) 110 if !hcEnable { 111 log.Warnf("[Health Check][Check] selfService instance %s:%d not enable healthcheck", 112 cachedInstance.Host(), cachedInstance.Port()) 113 return 114 } 115 116 request := &plugin.CheckRequest{ 117 QueryRequest: plugin.QueryRequest{ 118 InstanceId: cachedInstance.ID(), 119 Host: cachedInstance.Host(), 120 Port: cachedInstance.Port(), 121 Healthy: cachedInstance.Healthy(), 122 }, 123 CurTimeSec: currentTimeSec, 124 ExpireDurationSec: getExpireDurationSec(cachedInstance.Proto), 125 } 126 checkResp, err := checker.Check(request) 127 if err != nil { 128 log.Errorf("[Health Check][Check]fail to check selfService instance %s:%d, id is %s, err is %v", 129 cachedInstance.Host(), cachedInstance.Port(), cachedInstance.ID(), err) 130 return 131 } 132 if !checkResp.StayUnchanged { 133 code := setInsDbStatus(cachedInstance, checkResp.Healthy, checkResp.LastHeartbeatTimeSec) 134 if checkResp.Healthy { 135 // from unhealthy to healthy 136 log.Infof( 137 "[Health Check][Check]selfService instance change from unhealthy to healthy, id is %s, address is %s:%d", 138 cachedInstance.ID(), cachedInstance.Host(), cachedInstance.Port()) 139 } else { 140 // from healthy to unhealthy 141 log.Infof( 142 "[Health Check][Check]selfService instance change from healthy to unhealthy, id is %s, address is %s:%d", 143 cachedInstance.ID(), cachedInstance.Host(), cachedInstance.Port()) 144 } 145 if code != apimodel.Code_ExecuteSuccess { 146 log.Errorf( 147 "[Health Check][Check]fail to update selfService instance, id is %s, address is %s:%d, code is %d", 148 cachedInstance.ID(), cachedInstance.Host(), cachedInstance.Port(), code) 149 } 150 } 151 }