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

168 lines
4.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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
}