dubbo.apache.org/dubbo-go/v3@v3.1.1/metadata/report/delegate/delegate_report.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package delegate 19 20 import ( 21 "encoding/json" 22 "runtime/debug" 23 "sync" 24 "time" 25 ) 26 27 import ( 28 gxset "github.com/dubbogo/gost/container/set" 29 "github.com/dubbogo/gost/log/logger" 30 31 "github.com/go-co-op/gocron" 32 33 perrors "github.com/pkg/errors" 34 35 "go.uber.org/atomic" 36 ) 37 38 import ( 39 "dubbo.apache.org/dubbo-go/v3/common" 40 "dubbo.apache.org/dubbo-go/v3/common/constant" 41 "dubbo.apache.org/dubbo-go/v3/config/instance" 42 "dubbo.apache.org/dubbo-go/v3/metadata/definition" 43 "dubbo.apache.org/dubbo-go/v3/metadata/identifier" 44 ) 45 46 const ( 47 defaultMetadataReportRetryTimes int64 = 100 // max times to retry 48 defaultMetadataReportRetryPeriod int64 = 3 // cycle interval to retry, the unit is second 49 defaultMetadataReportCycleReport bool = true // cycle report or not 50 ) 51 52 // metadataReportRetry is a scheduler for retrying task 53 type metadataReportRetry struct { 54 retryPeriod int64 55 retryLimit int64 56 scheduler *gocron.Scheduler 57 job *gocron.Job 58 retryCounter *atomic.Int64 59 // if no failed report, wait how many times to run retry task. 60 retryTimesIfNonFail int64 61 } 62 63 // newMetadataReportRetry will create a scheduler for retry task 64 func newMetadataReportRetry(retryPeriod int64, retryLimit int64, retryFunc func() bool) (*metadataReportRetry, error) { 65 s1 := gocron.NewScheduler(time.UTC) 66 67 mrr := &metadataReportRetry{ 68 retryPeriod: retryPeriod, 69 retryLimit: retryLimit, 70 scheduler: s1, 71 retryCounter: atomic.NewInt64(0), 72 retryTimesIfNonFail: 600, 73 } 74 75 newJob, err := mrr.scheduler.Every(int(mrr.retryPeriod)).Seconds().Do( 76 func() { 77 mrr.retryCounter.Inc() 78 logger.Infof("start to retry task for metadata report. retry times: %v", mrr.retryCounter.Load()) 79 if mrr.retryCounter.Load() > mrr.retryLimit { 80 mrr.scheduler.Clear() 81 } else if retryFunc() && mrr.retryCounter.Load() > mrr.retryTimesIfNonFail { 82 mrr.scheduler.Clear() // may not interrupt the running job 83 } 84 }) 85 86 mrr.job = newJob 87 return mrr, err 88 } 89 90 // startRetryTask will make scheduler with retry task run 91 func (mrr *metadataReportRetry) startRetryTask() { 92 mrr.scheduler.StartAt(time.Now().Add(500 * time.Millisecond)) 93 mrr.scheduler.StartAsync() 94 } 95 96 // MetadataReport is a absolute delegate for MetadataReport 97 type MetadataReport struct { 98 reportUrl *common.URL 99 syncReport bool 100 metadataReportRetry *metadataReportRetry 101 102 failedReports map[*identifier.MetadataIdentifier]interface{} 103 failedReportsLock sync.RWMutex 104 105 // allMetadataReports store all the metdadata reports records in memory 106 allMetadataReports map[*identifier.MetadataIdentifier]interface{} 107 allMetadataReportsLock sync.RWMutex 108 } 109 110 // NewMetadataReport will create a MetadataReport with initiation 111 func NewMetadataReport() (*MetadataReport, error) { 112 url := instance.GetMetadataReportUrl() 113 if url == nil { 114 logger.Warn("the metadataReport URL is not configured, you should configure it.") 115 return nil, perrors.New("the metadataReport URL is not configured, you should configure it.") 116 } 117 bmr := &MetadataReport{ 118 reportUrl: url, 119 syncReport: url.GetParamBool(constant.SyncReportKey, false), 120 failedReports: make(map[*identifier.MetadataIdentifier]interface{}, 4), 121 allMetadataReports: make(map[*identifier.MetadataIdentifier]interface{}, 4), 122 } 123 124 mrr, err := newMetadataReportRetry( 125 url.GetParamInt(constant.RetryPeriodKey, defaultMetadataReportRetryPeriod), 126 url.GetParamInt(constant.RetryTimesKey, defaultMetadataReportRetryTimes), 127 bmr.retry, 128 ) 129 if err != nil { 130 return nil, err 131 } 132 133 bmr.metadataReportRetry = mrr 134 if url.GetParamBool(constant.CycleReportKey, defaultMetadataReportCycleReport) { 135 scheduler := gocron.NewScheduler(time.UTC) 136 _, err := scheduler.Every(1).Day().Do( 137 func() { 138 logger.Infof("start to publish all metadata in metadata report %s.", url.String()) 139 bmr.allMetadataReportsLock.RLock() 140 bmr.doHandlerMetadataCollection(bmr.allMetadataReports) 141 bmr.allMetadataReportsLock.RUnlock() 142 }) 143 if err != nil { 144 return nil, err 145 } 146 scheduler.StartAt(time.Now().Add(500 * time.Millisecond)) 147 scheduler.StartAsync() 148 } 149 return bmr, nil 150 } 151 152 // PublishAppMetadata delegate publish metadata info 153 func (mr *MetadataReport) PublishAppMetadata(identifier *identifier.SubscriberMetadataIdentifier, info *common.MetadataInfo) error { 154 report := instance.GetMetadataReportInstance() 155 return report.PublishAppMetadata(identifier, info) 156 } 157 158 // GetAppMetadata delegate get metadata info 159 func (mr *MetadataReport) GetAppMetadata(identifier *identifier.SubscriberMetadataIdentifier) (*common.MetadataInfo, error) { 160 report := instance.GetMetadataReportInstance() 161 return report.GetAppMetadata(identifier) 162 } 163 164 // retry will do metadata failed reports collection by call metadata report sdk 165 func (mr *MetadataReport) retry() bool { 166 mr.failedReportsLock.RLock() 167 defer mr.failedReportsLock.RUnlock() 168 return mr.doHandlerMetadataCollection(mr.failedReports) 169 } 170 171 // StoreProviderMetadata will delegate to call remote metadata's sdk to store provider service definition 172 func (mr *MetadataReport) StoreProviderMetadata(identifier *identifier.MetadataIdentifier, definer definition.ServiceDefiner) { 173 if mr.syncReport { 174 mr.storeMetadataTask(common.PROVIDER, identifier, definer) 175 } 176 go mr.storeMetadataTask(common.PROVIDER, identifier, definer) 177 } 178 179 // storeMetadataTask will delegate to call remote metadata's sdk to store 180 func (mr *MetadataReport) storeMetadataTask(role int, identifier *identifier.MetadataIdentifier, definer interface{}) { 181 logger.Infof("publish provider identifier and definition: Identifier :%v ; definition: %v .", identifier, definer) 182 mr.allMetadataReportsLock.Lock() 183 mr.allMetadataReports[identifier] = definer 184 mr.allMetadataReportsLock.Unlock() 185 186 mr.failedReportsLock.Lock() 187 delete(mr.failedReports, identifier) 188 mr.failedReportsLock.Unlock() 189 // data is store the json marshaled definition 190 var ( 191 data []byte 192 err error 193 ) 194 195 defer func() { 196 if r := recover(); r != nil { 197 mr.failedReportsLock.Lock() 198 mr.failedReports[identifier] = definer 199 mr.failedReportsLock.Unlock() 200 mr.metadataReportRetry.startRetryTask() 201 logger.Errorf("Failed to put provider metadata %v in %v, cause: %v\n%s\n", 202 identifier, string(data), r, string(debug.Stack())) 203 } 204 }() 205 206 data, err = json.Marshal(definer) 207 if err != nil { 208 logger.Errorf("storeProviderMetadataTask error in stage json.Marshal, msg is %+v", err) 209 panic(err) 210 } 211 report := instance.GetMetadataReportInstance() 212 if role == common.PROVIDER { 213 err = report.StoreProviderMetadata(identifier, string(data)) 214 } else if role == common.CONSUMER { 215 err = report.StoreConsumerMetadata(identifier, string(data)) 216 } 217 218 if err != nil { 219 logger.Errorf("storeProviderMetadataTask error in stage call metadata report to StoreProviderMetadata, msg is %+v", err) 220 } 221 } 222 223 // StoreConsumerMetadata will delegate to call remote metadata's sdk to store consumer side service definition 224 func (mr *MetadataReport) StoreConsumerMetadata(identifier *identifier.MetadataIdentifier, definer map[string]string) { 225 if mr.syncReport { 226 mr.storeMetadataTask(common.CONSUMER, identifier, definer) 227 } 228 go mr.storeMetadataTask(common.CONSUMER, identifier, definer) 229 } 230 231 // SaveServiceMetadata will delegate to call remote metadata's sdk to save service metadata 232 func (mr *MetadataReport) SaveServiceMetadata(identifier *identifier.ServiceMetadataIdentifier, url *common.URL) error { 233 report := instance.GetMetadataReportInstance() 234 if mr.syncReport { 235 return report.SaveServiceMetadata(identifier, url) 236 } 237 go func() { 238 if err := report.SaveServiceMetadata(identifier, url); err != nil { 239 logger.Warnf("report.SaveServiceMetadata(identifier:%v, url:%v) = error:%v", identifier, url, err) 240 } 241 }() 242 return nil 243 } 244 245 // RemoveServiceMetadata will delegate to call remote metadata's sdk to remove service metadata 246 func (mr *MetadataReport) RemoveServiceMetadata(identifier *identifier.ServiceMetadataIdentifier) error { 247 report := instance.GetMetadataReportInstance() 248 if mr.syncReport { 249 return report.RemoveServiceMetadata(identifier) 250 } 251 go func() { 252 if err := report.RemoveServiceMetadata(identifier); err != nil { 253 logger.Warnf("report.RemoveServiceMetadata(identifier:%v) = error:%v", identifier, err) 254 } 255 }() 256 return nil 257 } 258 259 // GetExportedURLs will delegate to call remote metadata's sdk to get exported urls 260 func (mr *MetadataReport) GetExportedURLs(identifier *identifier.ServiceMetadataIdentifier) ([]string, error) { 261 report := instance.GetMetadataReportInstance() 262 return report.GetExportedURLs(identifier) 263 } 264 265 // SaveSubscribedData will delegate to call remote metadata's sdk to save subscribed data 266 func (mr *MetadataReport) SaveSubscribedData(identifier *identifier.SubscriberMetadataIdentifier, urls []*common.URL) error { 267 urlStrList := make([]string, 0, len(urls)) 268 for _, url := range urls { 269 urlStrList = append(urlStrList, url.String()) 270 } 271 bytes, err := json.Marshal(urlStrList) 272 if err != nil { 273 return perrors.WithMessage(err, "Could not convert the array to json") 274 } 275 276 report := instance.GetMetadataReportInstance() 277 if mr.syncReport { 278 return report.SaveSubscribedData(identifier, string(bytes)) 279 } 280 go func() { 281 if err := report.SaveSubscribedData(identifier, string(bytes)); err != nil { 282 logger.Warnf("report.SaveSubscribedData(identifier:%v, string(bytes):%v) = error: %v", 283 identifier, string(bytes), err) 284 } 285 }() 286 return nil 287 } 288 289 // GetSubscribedURLs will delegate to call remote metadata's sdk to get subscribed urls 290 func (mr *MetadataReport) GetSubscribedURLs(identifier *identifier.SubscriberMetadataIdentifier) ([]string, error) { 291 report := instance.GetMetadataReportInstance() 292 return report.GetSubscribedURLs(identifier) 293 } 294 295 // GetServiceDefinition will delegate to call remote metadata's sdk to get service definitions 296 func (mr *MetadataReport) GetServiceDefinition(identifier *identifier.MetadataIdentifier) (string, error) { 297 report := instance.GetMetadataReportInstance() 298 return report.GetServiceDefinition(identifier) 299 } 300 301 // doHandlerMetadataCollection will store metadata to metadata support with given metadataMap 302 func (mr *MetadataReport) doHandlerMetadataCollection(metadataMap map[*identifier.MetadataIdentifier]interface{}) bool { 303 if len(metadataMap) == 0 { 304 return true 305 } 306 for e := range metadataMap { 307 if common.RoleType(common.PROVIDER).Role() == e.Side { 308 mr.StoreProviderMetadata(e, metadataMap[e].(*definition.FullServiceDefinition)) 309 } else if common.RoleType(common.CONSUMER).Role() == e.Side { 310 mr.StoreConsumerMetadata(e, metadataMap[e].(map[string]string)) 311 } 312 } 313 return false 314 } 315 316 func (mr *MetadataReport) GetConfigKeysByGroup(group string) (*gxset.HashSet, error) { 317 //TODO implement me 318 panic("implement me") 319 }