github.com/zly-app/zapp@v1.3.3/plugin/apollo_provider/provider.go (about) 1 package apollo_provider 2 3 import ( 4 "context" 5 "fmt" 6 "sync" 7 "time" 8 9 "go.uber.org/zap" 10 11 "github.com/zly-app/zapp/config" 12 "github.com/zly-app/zapp/config/apollo_sdk" 13 "github.com/zly-app/zapp/core" 14 "github.com/zly-app/zapp/logger" 15 ) 16 17 // 观察失败等待时间 18 var WatchErrWaitTime = time.Second * 5 19 20 type ApolloProvider struct { 21 app core.IApp 22 client *apollo_sdk.ApolloClient 23 24 watchNamespaces map[string]int // 观察的命名空间, value为notificationID 25 namespaceCallbackList map[string]KeyCallbacks // 命名空间回调列表 26 27 watchCtx context.Context 28 watchCtxCancel context.CancelFunc 29 30 // 用于锁 watchNamespaces, watchNamespaceList 31 mx sync.Mutex 32 } 33 34 // key回调列表 35 type KeyCallbacks map[string][]core.ConfigWatchProviderCallback 36 37 func (p *ApolloProvider) Inject(a ...interface{}) {} 38 func (p *ApolloProvider) Start() error { 39 go p.startWatchNamespace() 40 return nil 41 } 42 func (p *ApolloProvider) Close() error { 43 p.watchCtxCancel() 44 return nil 45 } 46 47 func NewApolloProvider(app core.IApp) *ApolloProvider { 48 client, err := config.GetApolloClient() 49 if err != nil { 50 app.Fatal("获取客户端失败", zap.Error(err)) 51 } 52 p := &ApolloProvider{ 53 app: app, 54 client: client, 55 watchNamespaces: make(map[string]int), 56 namespaceCallbackList: make(map[string]KeyCallbacks), 57 } 58 p.watchCtx, p.watchCtxCancel = context.WithCancel(app.BaseContext()) 59 return p 60 } 61 62 // 获取 63 func (p *ApolloProvider) Get(groupName, keyName string) ([]byte, error) { 64 if groupName == "" { 65 groupName = apollo_sdk.ApplicationNamespace 66 } 67 _, data, _, err := p.client.GetNamespaceData(groupName, true) 68 if err != nil { 69 return nil, err 70 } 71 value, ok := data.Configurations[keyName] 72 if !ok { 73 return nil, fmt.Errorf("配置数据不存在 groupName: %s, keyName: %s", groupName, keyName) 74 } 75 return []byte(value), nil 76 } 77 78 // watch 79 func (p *ApolloProvider) Watch(groupName, keyName string, callback core.ConfigWatchProviderCallback) error { 80 if groupName == "" { 81 groupName = apollo_sdk.ApplicationNamespace 82 } 83 _, data, _, err := p.client.GetNamespaceData(groupName, true) 84 if err != nil { 85 return err 86 } 87 _, ok := data.Configurations[keyName] 88 if !ok { 89 return fmt.Errorf("配置数据不存在 groupName: %s, keyName: %s", groupName, keyName) 90 } 91 92 // 添加观察命名空间 93 p.addWatchNamespace(groupName) 94 // 添加回调 95 p.addCallback(groupName, keyName, callback) 96 97 return nil 98 } 99 100 // 添加观察命名空间 101 func (p *ApolloProvider) addWatchNamespace(namespace string) { 102 p.mx.Lock() 103 defer p.mx.Unlock() 104 105 _, ok := p.watchNamespaces[namespace] 106 if !ok { 107 p.watchNamespaces[namespace] = 0 108 } 109 } 110 111 // 添加回调 112 func (p *ApolloProvider) addCallback(groupName, keyName string, callback core.ConfigWatchProviderCallback) { 113 p.mx.Lock() 114 defer p.mx.Unlock() 115 116 keyCallbacks, ok := p.namespaceCallbackList[groupName] 117 if !ok { 118 keyCallbacks = make(KeyCallbacks, 1) 119 p.namespaceCallbackList[groupName] = keyCallbacks 120 } 121 keyCallbacks[keyName] = append(keyCallbacks[keyName], callback) 122 } 123 124 // 开始观察命名空间 125 func (p *ApolloProvider) startWatchNamespace() { 126 for { 127 select { 128 case <-p.watchCtx.Done(): 129 return 130 default: 131 param := p.makeNotificationParam() 132 rsp, err := p.client.WaitNotification(p.watchCtx, param) 133 if err != nil { 134 logger.Log.Error("创建观察apollo通知失败", zap.Any("param", param), zap.Error(err)) 135 time.Sleep(WatchErrWaitTime) 136 continue 137 } 138 139 // 解析通知结果 140 p.parseNotificationRsp(rsp) 141 } 142 } 143 } 144 145 // 构建通知param 146 func (p *ApolloProvider) makeNotificationParam() []*apollo_sdk.NotificationParam { 147 p.mx.Lock() 148 param := make([]*apollo_sdk.NotificationParam, 0, len(p.watchNamespaces)) 149 for k, nid := range p.watchNamespaces { 150 param = append(param, &apollo_sdk.NotificationParam{ 151 NamespaceName: k, 152 NotificationId: nid, 153 }) 154 } 155 p.mx.Unlock() 156 return param 157 } 158 159 // 解析通知结果 160 func (p *ApolloProvider) parseNotificationRsp(rsp []*apollo_sdk.NotificationRsp) { 161 if len(rsp) == 0 { 162 return 163 } 164 165 p.mx.Lock() 166 defer p.mx.Unlock() 167 for _, v := range rsp { 168 p.watchNamespaces[v.NamespaceName] = v.NotificationId 169 go p.ReReqNamespaceData(v.NamespaceName) 170 } 171 } 172 173 // 重新请求命名空间数据 174 func (p *ApolloProvider) ReReqNamespaceData(namespace string) { 175 oldData, newData, changed, err := p.client.GetNamespaceData(namespace, true) 176 if err != nil { 177 p.app.Error("重新请求apollo命名空间数据失败", zap.String("namespace", namespace), zap.Error(err)) 178 return 179 } 180 if !changed { 181 return 182 } 183 184 p.mx.Lock() 185 defer p.mx.Unlock() 186 187 // 获取回调函数列表, 遍历回调 188 keyCallbacks, ok := p.namespaceCallbackList[namespace] 189 if !ok { 190 return 191 } 192 for key, callbacks := range keyCallbacks { 193 oldVale := oldData.Configurations[key] 194 newValue := newData.Configurations[key] 195 for _, fn := range callbacks { 196 go fn(namespace, key, []byte(oldVale), []byte(newValue)) 197 } 198 } 199 }