github.com/TeaOSLab/EdgeNode@v1.3.8/internal/nodes/origin_state_manager.go (about)

     1  // Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
     2  
     3  package nodes
     4  
     5  import (
     6  	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
     7  	teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
     8  	"github.com/TeaOSLab/EdgeNode/internal/events"
     9  	"github.com/TeaOSLab/EdgeNode/internal/goman"
    10  	"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
    11  	"github.com/TeaOSLab/EdgeNode/internal/trackers"
    12  	"github.com/iwind/TeaGo/Tea"
    13  	"sync"
    14  	"time"
    15  )
    16  
    17  var SharedOriginStateManager = NewOriginStateManager()
    18  
    19  func init() {
    20  	if !teaconst.IsMain {
    21  		return
    22  	}
    23  
    24  	events.On(events.EventLoaded, func() {
    25  		goman.New(func() {
    26  			SharedOriginStateManager.Start()
    27  		})
    28  	})
    29  	events.On(events.EventQuit, func() {
    30  		SharedOriginStateManager.Stop()
    31  	})
    32  }
    33  
    34  const (
    35  	maxOriginStates = 512 // 最多可以监控的源站状态数量
    36  )
    37  
    38  // OriginStateManager 源站状态管理
    39  type OriginStateManager struct {
    40  	stateMap map[int64]*OriginState // originId => *OriginState
    41  
    42  	ticker *time.Ticker
    43  	locker sync.RWMutex
    44  }
    45  
    46  // NewOriginStateManager 获取新管理对象
    47  func NewOriginStateManager() *OriginStateManager {
    48  	return &OriginStateManager{
    49  		stateMap: map[int64]*OriginState{},
    50  		ticker:   time.NewTicker(60 * time.Second),
    51  	}
    52  }
    53  
    54  // Start 启动
    55  func (this *OriginStateManager) Start() {
    56  	if Tea.IsTesting() {
    57  		this.ticker = time.NewTicker(10 * time.Second)
    58  	}
    59  	for range this.ticker.C {
    60  		err := this.Loop()
    61  		if err != nil {
    62  			remotelogs.Error("ORIGIN_MANAGER", err.Error())
    63  		}
    64  	}
    65  }
    66  
    67  func (this *OriginStateManager) Stop() {
    68  	if this.ticker != nil {
    69  		this.ticker.Stop()
    70  	}
    71  }
    72  
    73  // Loop 单次循环检查
    74  func (this *OriginStateManager) Loop() error {
    75  	var nodeConfig = sharedNodeConfig // 复制
    76  	if nodeConfig == nil {
    77  		return nil
    78  	}
    79  
    80  	var tr = trackers.Begin("CHECK_ORIGIN_STATES")
    81  	defer tr.End()
    82  
    83  	var currentStates = []*OriginState{}
    84  	this.locker.Lock()
    85  	for originId, state := range this.stateMap {
    86  		// 检查Origin是否正在使用
    87  		var originConfig = nodeConfig.FindOrigin(originId)
    88  		if originConfig == nil || !originConfig.IsOn {
    89  			delete(this.stateMap, originId)
    90  			continue
    91  		}
    92  		state.Config = originConfig
    93  		currentStates = append(currentStates, state)
    94  	}
    95  	this.locker.Unlock()
    96  
    97  	if len(currentStates) == 0 {
    98  		return nil
    99  	}
   100  
   101  	var count = len(currentStates)
   102  	var wg = &sync.WaitGroup{}
   103  	wg.Add(count)
   104  	for _, state := range currentStates {
   105  		go func(state *OriginState) {
   106  			defer wg.Done()
   107  			conn, _, err := OriginConnect(state.Config, 0, "", state.TLSHost)
   108  			if err == nil {
   109  				_ = conn.Close()
   110  
   111  				// 已经恢复正常
   112  				this.locker.Lock()
   113  				state.Config.IsOk = true
   114  				delete(this.stateMap, state.Config.Id)
   115  				this.locker.Unlock()
   116  
   117  				var reverseProxy = state.ReverseProxy
   118  				if reverseProxy != nil {
   119  					reverseProxy.ResetScheduling()
   120  				}
   121  			}
   122  		}(state)
   123  	}
   124  	wg.Wait()
   125  
   126  	return nil
   127  }
   128  
   129  // Fail 添加失败的源站
   130  func (this *OriginStateManager) Fail(origin *serverconfigs.OriginConfig, tlsHost string, reverseProxy *serverconfigs.ReverseProxyConfig, callback func()) {
   131  	if origin == nil || origin.Id <= 0 {
   132  		return
   133  	}
   134  
   135  	this.locker.Lock()
   136  	state, ok := this.stateMap[origin.Id]
   137  	var timestamp = time.Now().Unix()
   138  	if ok {
   139  		if state.UpdatedAt < timestamp-300 { // N 分钟之后重新计数
   140  			state.CountFails = 0
   141  			state.Config.IsOk = true
   142  		}
   143  
   144  		state.TLSHost = tlsHost
   145  		state.CountFails++
   146  		state.Config = origin
   147  		state.ReverseProxy = reverseProxy
   148  		state.UpdatedAt = timestamp
   149  
   150  		if origin.IsOk {
   151  			origin.IsOk = state.CountFails < 5 // 超过 N 次之后认为是异常
   152  
   153  			if !origin.IsOk {
   154  				if callback != nil {
   155  					callback()
   156  				}
   157  			}
   158  		}
   159  	} else {
   160  		// 同时最多监控 N 个源站地址
   161  		if len(this.stateMap) < maxOriginStates {
   162  			this.stateMap[origin.Id] = &OriginState{
   163  				CountFails:   1,
   164  				Config:       origin,
   165  				TLSHost:      tlsHost,
   166  				ReverseProxy: reverseProxy,
   167  				UpdatedAt:    timestamp,
   168  			}
   169  		}
   170  
   171  		origin.IsOk = true
   172  	}
   173  	this.locker.Unlock()
   174  }
   175  
   176  // Success 添加成功的源站
   177  func (this *OriginStateManager) Success(origin *serverconfigs.OriginConfig, callback func()) {
   178  	if origin == nil || origin.Id <= 0 {
   179  		return
   180  	}
   181  
   182  	if !origin.IsOk {
   183  		if callback != nil {
   184  			defer callback()
   185  		}
   186  	}
   187  
   188  	origin.IsOk = true
   189  	this.locker.Lock()
   190  	delete(this.stateMap, origin.Id)
   191  	this.locker.Unlock()
   192  }
   193  
   194  // IsAvailable 检查是否正常
   195  func (this *OriginStateManager) IsAvailable(originId int64) bool {
   196  	if originId <= 0 {
   197  		return true
   198  	}
   199  
   200  	this.locker.RLock()
   201  	_, ok := this.stateMap[originId]
   202  	this.locker.RUnlock()
   203  
   204  	return !ok
   205  }