dubbo.apache.org/dubbo-go/v3@v3.1.1/cluster/router/condition/dynamic_router.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 condition 19 20 import ( 21 "strconv" 22 "strings" 23 "sync" 24 ) 25 26 import ( 27 "github.com/dubbogo/gost/log/logger" 28 ) 29 30 import ( 31 "dubbo.apache.org/dubbo-go/v3/common" 32 conf "dubbo.apache.org/dubbo-go/v3/common/config" 33 "dubbo.apache.org/dubbo-go/v3/common/constant" 34 "dubbo.apache.org/dubbo-go/v3/config" 35 "dubbo.apache.org/dubbo-go/v3/config_center" 36 "dubbo.apache.org/dubbo-go/v3/protocol" 37 "dubbo.apache.org/dubbo-go/v3/remoting" 38 ) 39 40 type DynamicRouter struct { 41 conditionRouters []*StateRouter 42 routerConfig *config.RouterConfig 43 } 44 45 func (d *DynamicRouter) Route(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker { 46 if len(invokers) == 0 || len(d.conditionRouters) == 0 { 47 return invokers 48 } 49 50 for _, router := range d.conditionRouters { 51 invokers = router.Route(invokers, url, invocation) 52 } 53 return invokers 54 } 55 56 func (d *DynamicRouter) URL() *common.URL { 57 return nil 58 } 59 60 func (d *DynamicRouter) Process(event *config_center.ConfigChangeEvent) { 61 if event.ConfigType == remoting.EventTypeDel { 62 d.routerConfig = nil 63 d.conditionRouters = make([]*StateRouter, 0) 64 } else { 65 routerConfig, err := parseRoute(event.Value.(string)) 66 if err != nil { 67 logger.Warnf("[condition router]Build a new condition route config error, %+v and we will use the original condition rule configuration.", err) 68 return 69 } 70 d.routerConfig = routerConfig 71 conditions, err := generateConditions(d.routerConfig) 72 if err != nil { 73 logger.Warnf("[condition router]Build a new condition route config error, %+v and we will use the original condition rule configuration.", err) 74 return 75 } 76 d.conditionRouters = conditions 77 } 78 } 79 80 func generateConditions(routerConfig *config.RouterConfig) ([]*StateRouter, error) { 81 if routerConfig == nil { 82 return make([]*StateRouter, 0), nil 83 } 84 conditionRouters := make([]*StateRouter, 0, len(routerConfig.Conditions)) 85 for _, conditionRule := range routerConfig.Conditions { 86 url, err := common.NewURL("condition://") 87 if err != nil { 88 return nil, err 89 } 90 url.AddParam(constant.RuleKey, conditionRule) 91 url.AddParam(constant.ForceKey, strconv.FormatBool(*routerConfig.Force)) 92 url.AddParam(constant.EnabledKey, strconv.FormatBool(*routerConfig.Enabled)) 93 conditionRoute, err := NewConditionStateRouter(url) 94 if err != nil { 95 return nil, err 96 } 97 conditionRouters = append(conditionRouters, conditionRoute) 98 } 99 return conditionRouters, nil 100 } 101 102 // ServiceRouter is Service level router 103 type ServiceRouter struct { 104 DynamicRouter 105 } 106 107 func NewServiceRouter() *ServiceRouter { 108 return &ServiceRouter{} 109 } 110 111 func (s *ServiceRouter) Priority() int64 { 112 return 140 113 } 114 115 func (s *ServiceRouter) Notify(invokers []protocol.Invoker) { 116 if len(invokers) == 0 { 117 return 118 } 119 url := invokers[0].GetURL() 120 if url == nil { 121 logger.Error("Failed to notify a dynamically condition rule, because url is empty") 122 return 123 } 124 125 dynamicConfiguration := conf.GetEnvInstance().GetDynamicConfiguration() 126 if dynamicConfiguration == nil { 127 logger.Infof("Config center does not start, Condition router will not be enabled") 128 return 129 } 130 key := strings.Join([]string{url.ColonSeparatedKey(), constant.ConditionRouterRuleSuffix}, "") 131 dynamicConfiguration.AddListener(key, s) 132 value, err := dynamicConfiguration.GetRule(key) 133 if err != nil { 134 logger.Errorf("Failed to query condition rule, key=%s, err=%v", key, err) 135 return 136 } 137 s.Process(&config_center.ConfigChangeEvent{Key: key, Value: value, ConfigType: remoting.EventTypeAdd}) 138 } 139 140 // ApplicationRouter is Application level router 141 type ApplicationRouter struct { 142 DynamicRouter 143 application string 144 currentApplication string 145 mu sync.Mutex 146 } 147 148 func NewApplicationRouter() *ApplicationRouter { 149 applicationName := config.GetApplicationConfig().Name 150 a := &ApplicationRouter{ 151 currentApplication: applicationName, 152 } 153 154 dynamicConfiguration := conf.GetEnvInstance().GetDynamicConfiguration() 155 if dynamicConfiguration != nil { 156 dynamicConfiguration.AddListener(strings.Join([]string{applicationName, constant.ConditionRouterRuleSuffix}, ""), a) 157 } 158 return a 159 } 160 161 func (a *ApplicationRouter) Priority() int64 { 162 return 145 163 } 164 165 func (a *ApplicationRouter) Notify(invokers []protocol.Invoker) { 166 if len(invokers) == 0 { 167 return 168 } 169 url := invokers[0].GetURL() 170 if url == nil { 171 logger.Error("Failed to notify a dynamically condition rule, because url is empty") 172 return 173 } 174 providerApplicaton := url.GetParam("application", "") 175 if providerApplicaton == "" || providerApplicaton == a.currentApplication { 176 logger.Warn("condition router get providerApplication is empty, will not subscribe to provider app rules.") 177 return 178 } 179 180 a.mu.Lock() 181 defer a.mu.Unlock() 182 183 if providerApplicaton != a.application { 184 dynamicConfiguration := conf.GetEnvInstance().GetDynamicConfiguration() 185 if dynamicConfiguration == nil { 186 logger.Infof("Config center does not start, Condition router will not be enabled") 187 return 188 } 189 190 if a.application != "" { 191 dynamicConfiguration.RemoveListener(strings.Join([]string{a.application, constant.ConditionRouterRuleSuffix}, ""), a) 192 } 193 194 key := strings.Join([]string{providerApplicaton, constant.ConditionRouterRuleSuffix}, "") 195 dynamicConfiguration.AddListener(key, a) 196 a.application = providerApplicaton 197 value, err := dynamicConfiguration.GetRule(key) 198 if err != nil { 199 logger.Errorf("Failed to query condition rule, key=%s, err=%v", key, err) 200 return 201 } 202 a.Process(&config_center.ConfigChangeEvent{Key: key, Value: value, ConfigType: remoting.EventTypeUpdate}) 203 } 204 }