github.com/polarismesh/polaris@v1.17.8/plugin/healthchecker/memory/checker_memory.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 heartbeatmemory
    19  
    20  import (
    21  	"context"
    22  	"sync/atomic"
    23  
    24  	commonLog "github.com/polarismesh/polaris/common/log"
    25  	commontime "github.com/polarismesh/polaris/common/time"
    26  	"github.com/polarismesh/polaris/common/utils"
    27  	"github.com/polarismesh/polaris/plugin"
    28  )
    29  
    30  // 把操作记录记录到日志文件中
    31  const (
    32  	// PluginName plugin name
    33  	PluginName = "heartbeatMemory"
    34  )
    35  
    36  var log = commonLog.GetScopeOrDefaultByName(commonLog.HealthcheckLoggerName)
    37  
    38  // HeartbeatRecord record for heartbeat
    39  type HeartbeatRecord struct {
    40  	Server     string
    41  	CurTimeSec int64
    42  	Count      int64
    43  }
    44  
    45  // MemoryHealthChecker memory health checker
    46  type MemoryHealthChecker struct {
    47  	hbRecords      *utils.SyncMap[string, *HeartbeatRecord]
    48  	suspendTimeSec int64
    49  }
    50  
    51  // Name return plugin name
    52  func (r *MemoryHealthChecker) Name() string {
    53  	return PluginName
    54  }
    55  
    56  // Initialize initialize plugin
    57  func (r *MemoryHealthChecker) Initialize(c *plugin.ConfigEntry) error {
    58  	r.hbRecords = utils.NewSyncMap[string, *HeartbeatRecord]()
    59  	return nil
    60  }
    61  
    62  // Destroy plugin destruction
    63  func (r *MemoryHealthChecker) Destroy() error {
    64  	return nil
    65  }
    66  
    67  // Type for health check plugin, only one same type plugin is allowed
    68  func (r *MemoryHealthChecker) Type() plugin.HealthCheckType {
    69  	return plugin.HealthCheckerHeartbeat
    70  }
    71  
    72  // Report process heartbeat info report
    73  func (r *MemoryHealthChecker) Report(ctx context.Context, request *plugin.ReportRequest) error {
    74  	record := &HeartbeatRecord{
    75  		Server:     request.LocalHost,
    76  		CurTimeSec: request.CurTimeSec,
    77  		Count:      request.Count,
    78  	}
    79  	r.hbRecords.Store(request.InstanceId, record)
    80  	log.Debugf("[HealthCheck][MemoryCheck]add hb record, instanceId %s, record %+v", request.InstanceId, record)
    81  	return nil
    82  }
    83  
    84  // Query queries the heartbeat time
    85  func (r *MemoryHealthChecker) Query(ctx context.Context, request *plugin.QueryRequest) (*plugin.QueryResponse, error) {
    86  	record, ok := r.hbRecords.Load(request.InstanceId)
    87  	if !ok {
    88  		return &plugin.QueryResponse{
    89  			LastHeartbeatSec: 0,
    90  		}, nil
    91  	}
    92  	log.Debugf("[HealthCheck][MemoryCheck]query hb record, instanceId %s, record %+v", request.InstanceId, record)
    93  	return &plugin.QueryResponse{
    94  		Server:           record.Server,
    95  		LastHeartbeatSec: record.CurTimeSec,
    96  		Count:            record.Count,
    97  	}, nil
    98  }
    99  
   100  func (r *MemoryHealthChecker) skipCheck(instanceId string, expireDurationSec int64) bool {
   101  	suspendTimeSec := r.SuspendTimeSec()
   102  	localCurTimeSec := commontime.CurrentMillisecond() / 1000
   103  	if suspendTimeSec > 0 && localCurTimeSec >= suspendTimeSec && localCurTimeSec-suspendTimeSec < expireDurationSec {
   104  		log.Infof("[Health Check][MemoryCheck]health check redis suspended, "+
   105  			"suspendTimeSec is %d, localCurTimeSec is %d, expireDurationSec is %d, instanceId %s",
   106  			suspendTimeSec, localCurTimeSec, expireDurationSec, instanceId)
   107  		return true
   108  	}
   109  	return false
   110  }
   111  
   112  // Check Report process the instance check
   113  func (r *MemoryHealthChecker) Check(request *plugin.CheckRequest) (*plugin.CheckResponse, error) {
   114  	queryResp, err := r.Query(context.Background(), &request.QueryRequest)
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  	lastHeartbeatTime := queryResp.LastHeartbeatSec
   119  	checkResp := &plugin.CheckResponse{
   120  		LastHeartbeatTimeSec: lastHeartbeatTime,
   121  	}
   122  	curTimeSec := request.CurTimeSec()
   123  	log.Debugf("[HealthCheck][MemoryCheck]check hb record, cur is %d, last is %d", curTimeSec, lastHeartbeatTime)
   124  	if r.skipCheck(request.InstanceId, int64(request.ExpireDurationSec)) {
   125  		checkResp.StayUnchanged = true
   126  		return checkResp, nil
   127  	}
   128  	if curTimeSec > lastHeartbeatTime {
   129  		if curTimeSec-lastHeartbeatTime >= int64(request.ExpireDurationSec) {
   130  			// 心跳超时
   131  			checkResp.Healthy = false
   132  
   133  			if request.Healthy {
   134  				log.Infof("[Health Check][MemoryCheck]health check expired, "+
   135  					"last hb timestamp is %d, curTimeSec is %d, expireDurationSec is %d, instanceId %s",
   136  					lastHeartbeatTime, curTimeSec, request.ExpireDurationSec, request.InstanceId)
   137  			} else {
   138  				checkResp.StayUnchanged = true
   139  			}
   140  			return checkResp, nil
   141  		}
   142  	}
   143  	checkResp.Healthy = true
   144  	if !request.Healthy {
   145  		log.Infof("[Health Check][MemoryCheck]health check resumed, "+
   146  			"last hb timestamp is %d, curTimeSec is %d, expireDurationSec is %d instanceId %s",
   147  			lastHeartbeatTime, curTimeSec, request.ExpireDurationSec, request.InstanceId)
   148  	} else {
   149  		checkResp.StayUnchanged = true
   150  	}
   151  
   152  	return checkResp, nil
   153  }
   154  
   155  // Delete delete the id
   156  func (r *MemoryHealthChecker) Delete(ctx context.Context, id string) error {
   157  	r.hbRecords.Delete(id)
   158  	return nil
   159  }
   160  
   161  func (r *MemoryHealthChecker) Suspend() {
   162  	curTimeMilli := commontime.CurrentMillisecond() / 1000
   163  	log.Infof("[Health Check][MemoryCheck] suspend checker, start time %d", curTimeMilli)
   164  	atomic.StoreInt64(&r.suspendTimeSec, curTimeMilli)
   165  }
   166  
   167  // SuspendTimeSec get suspend time in seconds
   168  func (r *MemoryHealthChecker) SuspendTimeSec() int64 {
   169  	return atomic.LoadInt64(&r.suspendTimeSec)
   170  }
   171  
   172  func (r *MemoryHealthChecker) DebugHandlers() []plugin.DebugHandler {
   173  	return []plugin.DebugHandler{}
   174  }
   175  
   176  func init() {
   177  	d := &MemoryHealthChecker{}
   178  	plugin.RegisterPlugin(d.Name(), d)
   179  }