github.com/polarismesh/polaris@v1.17.8/service/healthcheck/report.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 apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage" 26 27 api "github.com/polarismesh/polaris/common/api/v1" 28 "github.com/polarismesh/polaris/common/model" 29 "github.com/polarismesh/polaris/common/utils" 30 "github.com/polarismesh/polaris/plugin" 31 ) 32 33 // checkHeartbeatInstance 检查心跳实例请求参数 34 // 检查是否存在token,以及 id或者四元组 35 // 注意:心跳上报只允许从client上报,因此token只会存在req中 36 func checkHeartbeatInstance(req *apiservice.Instance) (string, *apiservice.Response) { 37 if req == nil { 38 return "", api.NewInstanceResponse(apimodel.Code_EmptyRequest, req) 39 } 40 if req.GetId() != nil { 41 if req.GetId().GetValue() == "" { 42 return "", api.NewInstanceResponse(apimodel.Code_InvalidInstanceID, req) 43 } 44 return req.GetId().GetValue(), nil 45 } 46 return utils.CheckInstanceTetrad(req) 47 } 48 49 const max404Count = 3 50 51 func (s *Server) checkInstanceExists(ctx context.Context, id string) (int64, *model.Instance, apimodel.Code) { 52 ins := s.instanceCache.GetInstance(id) 53 if ins != nil { 54 return -1, ins, apimodel.Code_ExecuteSuccess 55 } 56 resp, err := s.defaultChecker.Query(ctx, &plugin.QueryRequest{ 57 InstanceId: id, 58 }) 59 if nil != err { 60 log.Errorf("[healthcheck]fail to query report count by id %s, err: %v", id, err) 61 return -1, nil, apimodel.Code_ExecuteSuccess 62 } 63 if resp.Count > max404Count { 64 return resp.Count, nil, apimodel.Code_NotFoundResource 65 } 66 return resp.Count, nil, apimodel.Code_ExecuteSuccess 67 } 68 69 func (s *Server) getHealthChecker(id string) plugin.HealthChecker { 70 insCache := s.cacheProvider.GetInstance(id) 71 if insCache == nil { 72 insCache = s.cacheProvider.GetSelfServiceInstance(id) 73 } 74 if insCache == nil { 75 return s.defaultChecker 76 } 77 checker, ok := s.checkers[int32(insCache.HealthCheck().GetType())] 78 if !ok { 79 return s.defaultChecker 80 } 81 return checker 82 } 83 84 func (s *Server) doReport(ctx context.Context, instance *apiservice.Instance) *apiservice.Response { 85 if !s.hcOpt.Open || len(s.checkers) == 0 { 86 return api.NewResponse(apimodel.Code_HealthCheckNotOpen) 87 } 88 id, errRsp := checkHeartbeatInstance(instance) 89 if errRsp != nil { 90 return errRsp 91 } 92 request := &plugin.ReportRequest{ 93 QueryRequest: plugin.QueryRequest{ 94 InstanceId: id, 95 Host: instance.GetHost().GetValue(), 96 Port: instance.GetPort().GetValue(), 97 }, 98 LocalHost: s.localHost, 99 CurTimeSec: time.Now().Unix() - s.timeAdjuster.GetDiff(), 100 } 101 code, err := s.baseReport(ctx, id, request) 102 if err != nil { 103 log.Errorf("[Heartbeat][Server] fail to do report for %s:%d, id is %s, err is %v", 104 instance.GetHost().GetValue(), instance.GetPort().GetValue(), id, err) 105 return api.NewInstanceResponse(apimodel.Code_HeartbeatException, instance) 106 } 107 return api.NewInstanceResponse(code, instance) 108 } 109 110 func (s *Server) doReports(ctx context.Context, beats []*apiservice.InstanceHeartbeat) *apiservice.Response { 111 if !s.hcOpt.Open || len(s.checkers) == 0 { 112 return api.NewResponse(apimodel.Code_HealthCheckNotOpen) 113 } 114 for i := range beats { 115 beat := beats[i] 116 request := &plugin.ReportRequest{ 117 QueryRequest: plugin.QueryRequest{ 118 InstanceId: beat.InstanceId, 119 Host: beat.Host, 120 Port: beat.Port, 121 }, 122 LocalHost: s.localHost, 123 CurTimeSec: time.Now().Unix() - s.timeAdjuster.GetDiff(), 124 } 125 code, err := s.baseReport(ctx, beat.InstanceId, request) 126 if err != nil { 127 log.Errorf("[Heartbeat][Server]fail to do report for %s:%d, id is %s, err is %v", 128 beat.GetHost(), beat.GetPort(), beat.GetInstanceId(), err) 129 return api.NewInstanceResponse(apimodel.Code_HeartbeatException, nil) 130 } 131 if code != apimodel.Code_ExecuteSuccess { 132 log.Warnf("[Heartbeat][Server] do report for %s:%d, id is %s, code is %v", 133 beat.GetHost(), beat.GetPort(), beat.GetInstanceId(), code) 134 } 135 } 136 return api.NewResponse(apimodel.Code_ExecuteSuccess) 137 } 138 139 func (s *Server) baseReport(ctx context.Context, id string, reportReq *plugin.ReportRequest) (apimodel.Code, error) { 140 count, ins, code := s.checkInstanceExists(ctx, id) 141 checker := s.getHealthChecker(id) 142 reportReq.Count = count + 1 143 err := checker.Report(ctx, reportReq) 144 if nil != ins { 145 event := &model.InstanceEvent{ 146 Id: id, 147 Instance: ins.Proto, 148 EType: model.EventInstanceSendHeartbeat, 149 } 150 event.InjectMetadata(ctx) 151 s.publishInstanceEvent(ins.ServiceID, *event) 152 } 153 return code, err 154 }