xframe/vendor/github.com/polarismesh/polaris-go/pkg/flow/notify.go

168 lines
4.8 KiB
Go
Raw Normal View History

2024-10-12 12:55:20 +08:00
/**
* Tencent is pleased to support the open source community by making polaris-go available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package flow
import (
"context"
"fmt"
"sync"
"sync/atomic"
"time"
"github.com/polarismesh/polaris-go/pkg/log"
"github.com/polarismesh/polaris-go/pkg/model"
"github.com/polarismesh/polaris-go/pkg/plugin/common"
)
const (
keySourceRoute = "sourceRoute"
keyDstRoute = "destinationRoute"
keyDstRateLimit = "destinationRateLimit"
keyDstInstances = "destinationInstances"
keyDstServices = "destinationServices"
)
// ContextKey 上下文标识
type ContextKey struct {
// 服务信息
ServiceKey *model.ServiceKey
// 操作信息
Operation string
}
// String ToString方法
func (c ContextKey) String() string {
return fmt.Sprintf("{ServiceKey: %s, Operation: %s}", *c.ServiceKey, c.Operation)
}
// SingleNotifyContext 同步调用回调上下文
type SingleNotifyContext struct {
name *ContextKey
notifier *common.Notifier
}
// NewSingleNotifyContext 创建回调上下文
func NewSingleNotifyContext(name *ContextKey, notifier *common.Notifier) *SingleNotifyContext {
return &SingleNotifyContext{name: name, notifier: notifier}
}
// Err 返回异常信息返回异常信息
func (s *SingleNotifyContext) Err() model.SDKError {
return s.notifier.GetError()
}
// Wait notify 异步任务执行回调函数
func (s *SingleNotifyContext) Wait(timeout time.Duration) bool {
afterTimer := time.After(timeout)
select {
case <-afterTimer:
return true
case <-s.notifier.GetContext().Done():
log.GetBaseLogger().Debugf("context %s has been notified", *s.name)
return false
}
}
// CombineNotifyContext 复合的回调上下文,等待所有的子回调都返回才会触发回调
type CombineNotifyContext struct {
svcKey *model.ServiceKey
waitCount int32
notifiers []*SingleNotifyContext
doneContextKeys *model.SyncHashSet
}
// NewCombineNotifyContext 创建复合回调上下文
func NewCombineNotifyContext(svcKey *model.ServiceKey, notifiers []*SingleNotifyContext) *CombineNotifyContext {
maxWaitCount := len(notifiers)
combineCtx := &CombineNotifyContext{
svcKey: svcKey,
notifiers: notifiers,
waitCount: int32(maxWaitCount),
doneContextKeys: model.NewSyncHashSet(),
}
return combineCtx
}
// IsDone 是否已经完成
func (c *CombineNotifyContext) IsDone() bool {
log.GetBaseLogger().Debugf("CombineNotifyContext waitCount %d", atomic.LoadInt32(&c.waitCount))
return atomic.LoadInt32(&c.waitCount) <= 0
}
// Errs 获取错误信息集合
func (c *CombineNotifyContext) Errs() map[ContextKey]model.SDKError {
var errs = make(map[ContextKey]model.SDKError, len(c.notifiers))
for _, notifier := range c.notifiers {
err := notifier.Err()
if err != nil {
errs[*notifier.name] = err
}
}
return errs
}
// logNotifier 打印通知日志
func (c *CombineNotifyContext) logNotifier(operation string, notifier *SingleNotifyContext, restWait int32) {
log.GetBaseLogger().Debugf("notifier %s of %s has been notified, rest %v", *notifier.name, c.svcKey, restWait)
}
// Wait notify 异步任务执行回调函数
// 返回值,是否超时
func (c *CombineNotifyContext) Wait(timeout time.Duration) (exceedTime bool) {
var restWait = atomic.LoadInt32(&c.waitCount)
if restWait == 0 {
return false
}
log.GetBaseLogger().Debugf("notifiers of %s start to wait, rest %d", *c.svcKey, restWait)
doneKeyChan := make(chan string)
ctx, cancel := context.WithCancel(context.Background())
go func() {
for {
select {
case <-ctx.Done():
return
case key := <-doneKeyChan:
c.doneContextKeys.Add(key)
}
}
}()
wg := &sync.WaitGroup{}
wg.Add(int(restWait))
for _, notifierValue := range c.notifiers {
if c.doneContextKeys.Contains(notifierValue.name.Operation) {
continue
}
go func(notifier *SingleNotifyContext) {
defer wg.Done()
afterTimer := time.After(timeout)
select {
case <-afterTimer:
return
case <-notifier.notifier.GetContext().Done():
doneKeyChan <- notifier.name.Operation
nextWait := atomic.AddInt32(&c.waitCount, -1)
c.logNotifier(notifier.name.Operation, notifier, nextWait)
}
}(notifierValue)
}
wg.Wait()
cancel()
// 如果没有waitCount还是大于0说明还需要远程获取信息
return atomic.LoadInt32(&c.waitCount) > 0
}