168 lines
4.8 KiB
Go
168 lines
4.8 KiB
Go
|
/**
|
|||
|
* 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
|
|||
|
}
|