github.com/polarismesh/polaris@v1.17.8/config/watcher.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 config 19 20 import ( 21 "context" 22 "sync" 23 24 apiconfig "github.com/polarismesh/specification/source/go/api/v1/config_manage" 25 "go.uber.org/zap" 26 27 "github.com/polarismesh/polaris/common/eventhub" 28 "github.com/polarismesh/polaris/common/model" 29 "github.com/polarismesh/polaris/common/utils" 30 ) 31 32 const ( 33 QueueSize = 10240 34 ) 35 36 type FileReleaseCallback func(clientId string, rsp *apiconfig.ConfigClientResponse) bool 37 38 type watchContext struct { 39 watchConfigFiles []*apiconfig.ClientConfigFileInfo 40 clientId string 41 fileReleaseCb FileReleaseCallback 42 ClientVersion uint64 43 } 44 45 // watchCenter 处理客户端订阅配置请求,监听配置文件发布事件通知客户端 46 type watchCenter struct { 47 connManager *connManager 48 subCtx *eventhub.SubscribtionContext 49 lock sync.Mutex 50 // fileId -> clientId -> watchContext 51 configFileWatchers *utils.SyncMap[string, *utils.SyncMap[string, *watchContext]] 52 } 53 54 // NewWatchCenter 创建一个客户端监听配置发布的处理中心 55 func NewWatchCenter() (*watchCenter, error) { 56 wc := &watchCenter{ 57 configFileWatchers: utils.NewSyncMap[string, *utils.SyncMap[string, *watchContext]](), 58 } 59 60 var err error 61 wc.subCtx, err = eventhub.Subscribe(eventhub.ConfigFilePublishTopic, wc, eventhub.WithQueueSize(QueueSize)) 62 if err != nil { 63 return nil, err 64 } 65 return wc, nil 66 } 67 68 // PreProcess do preprocess logic for event 69 func (wc *watchCenter) PreProcess(_ context.Context, e any) any { 70 return e 71 } 72 73 // OnEvent event process logic 74 func (wc *watchCenter) OnEvent(ctx context.Context, arg any) error { 75 event, ok := arg.(*eventhub.PublishConfigFileEvent) 76 if !ok { 77 log.Warn("[Config][Watcher] receive invalid event type") 78 return nil 79 } 80 wc.notifyToWatchers(event.Message) 81 return nil 82 } 83 84 // AddWatcher 新增订阅者 85 func (wc *watchCenter) AddWatcher(clientId string, watchConfigFiles []*apiconfig.ClientConfigFileInfo, 86 fileReleaseCb FileReleaseCallback) { 87 if len(watchConfigFiles) == 0 { 88 return 89 } 90 for _, file := range watchConfigFiles { 91 watchFileId := utils.GenFileId(file.Namespace.GetValue(), file.Group.GetValue(), file.FileName.GetValue()) 92 log.Info("[Config][Watcher] add watcher.", zap.Any("client-id", clientId), 93 zap.String("watch-file-id", watchFileId), zap.Uint64("client-version", file.Version.GetValue())) 94 95 watchers, _ := wc.configFileWatchers.ComputeIfAbsent(watchFileId, 96 func(k string) *utils.SyncMap[string, *watchContext] { 97 newWatchers := utils.NewSyncMap[string, *watchContext]() 98 return newWatchers 99 }) 100 watchers.Store(clientId, &watchContext{ 101 clientId: clientId, 102 fileReleaseCb: fileReleaseCb, 103 ClientVersion: file.Version.GetValue(), 104 watchConfigFiles: watchConfigFiles, 105 }) 106 } 107 } 108 109 // RemoveWatcher 删除订阅者 110 func (wc *watchCenter) RemoveWatcher(clientId string, watchConfigFiles []*apiconfig.ClientConfigFileInfo) { 111 if len(watchConfigFiles) == 0 { 112 return 113 } 114 115 for _, file := range watchConfigFiles { 116 watchFileId := utils.GenFileId(file.Namespace.GetValue(), file.Group.GetValue(), file.FileName.GetValue()) 117 watchers, ok := wc.configFileWatchers.Load(watchFileId) 118 if !ok { 119 continue 120 } 121 watchers.Delete(clientId) 122 } 123 } 124 125 func (wc *watchCenter) notifyToWatchers(publishConfigFile *model.SimpleConfigFileRelease) { 126 watchFileId := utils.GenFileId(publishConfigFile.Namespace, publishConfigFile.Group, publishConfigFile.FileName) 127 128 log.Info("[Config][Watcher] received config file publish message.", zap.String("file", watchFileId)) 129 watchers, ok := wc.configFileWatchers.Load(watchFileId) 130 if !ok { 131 return 132 } 133 134 response := GenConfigFileResponse(publishConfigFile.Namespace, publishConfigFile.Group, 135 publishConfigFile.FileName, "", publishConfigFile.Md5, publishConfigFile.Version) 136 137 waitNotifiers := watchers.Values() 138 for _, watchCtx := range waitNotifiers { 139 clientId := watchCtx.clientId 140 if watchCtx.ClientVersion < publishConfigFile.Version { 141 watchCtx.fileReleaseCb(clientId, response) 142 log.Info("[Config][Watcher] notify to client.", 143 zap.String("file", watchFileId), zap.String("clientId", clientId), 144 zap.Uint64("version", publishConfigFile.Version)) 145 } else { 146 log.Info("[Config][Watcher] notify to client ignore.", 147 zap.String("file", watchFileId), zap.String("clientId", clientId), 148 zap.Uint64("client-version", watchCtx.ClientVersion), 149 zap.Uint64("version", publishConfigFile.Version)) 150 } 151 } 152 }