This is an automated email from the ASF dual-hosted git repository.

liujun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git


The following commit(s) were added to refs/heads/main by this push:
     new 8035430c1 Design and implement new conditional rules V3.1 (#2686)
8035430c1 is described below

commit 8035430c1b3f4d8c4e3b3ef8ff3eac26daeb8954
Author: YarBor <[email protected]>
AuthorDate: Tue Jun 11 18:03:41 2024 +0800

    Design and implement new conditional rules V3.1 (#2686)
---
 cluster/router/condition/dynamic_router.go |  45 ++++---
 cluster/router/condition/route.go          | 172 +++++++++++++++++++++++---
 cluster/router/condition/router_test.go    | 190 +++++++++++++++++++----------
 common/constant/key.go                     |  47 +++----
 config/router_config.go                    |  18 ++-
 5 files changed, 352 insertions(+), 120 deletions(-)

diff --git a/cluster/router/condition/dynamic_router.go 
b/cluster/router/condition/dynamic_router.go
index 38e718736..6603d9bad 100644
--- a/cluster/router/condition/dynamic_router.go
+++ b/cluster/router/condition/dynamic_router.go
@@ -40,14 +40,15 @@ import (
        "gopkg.in/yaml.v2"
 )
 
-type conditionRoute []*StateRouter
+// for version 3.0-
+type stateRouters []*StateRouter
 
-func (p conditionRoute) route(invokers []protocol.Invoker, url *common.URL, 
invocation protocol.Invocation) []protocol.Invoker {
+func (p stateRouters) route(invokers []protocol.Invoker, url *common.URL, 
invocation protocol.Invocation) []protocol.Invoker {
        if len(invokers) == 0 || len(p) == 0 {
                return invokers
        }
        for _, router := range p {
-               invokers, _ = router.Route(invokers, url, invocation)
+               invokers = router.Route(invokers, url, invocation)
                if len(invokers) == 0 {
                        break
                }
@@ -55,18 +56,18 @@ func (p conditionRoute) route(invokers []protocol.Invoker, 
url *common.URL, invo
        return invokers
 }
 
-type multiplyConditionRoute []*StateRouter
+type multiplyConditionRoute []*MultiDestRouter
 
 func (m multiplyConditionRoute) route(invokers []protocol.Invoker, url 
*common.URL, invocation protocol.Invocation) []protocol.Invoker {
        if len(invokers) == 0 || len(m) == 0 {
                return invokers
        }
        for _, router := range m {
-               matchInvokers, isMatch := router.Route(invokers, url, 
invocation)
-               if !isMatch || (len(matchInvokers) == 0 && !router.force) {
+               res, isMatchWhen := router.Route(invokers, url, invocation)
+               if !isMatchWhen || (len(res) == 0 && 
invocation.GetAttachmentInterface(constant.TrafficDisableKey) == nil && 
!router.force) {
                        continue
                }
-               return matchInvokers
+               return res
        }
        return []protocol.Invoker{}
 }
@@ -96,8 +97,10 @@ func (d *DynamicRouter) Route(invokers []protocol.Invoker, 
url *common.URL, invo
        }
        if cr != nil {
                res := cr.route(invokers, url, invocation)
-               if len(res) == 0 && !force {
-                       return invokers
+               if len(res) == 0 {
+                       if 
invocation.GetAttachmentInterface(constant.TrafficDisableKey) == nil && !force {
+                               return invokers
+                       }
                }
                return res
        } else {
@@ -176,21 +179,33 @@ func generateMultiConditionRoute(rawConfig string) 
(multiplyConditionRoute, bool
                return nil, false, false, err
        }
 
-       force, enable := routerConfig.Enabled, routerConfig.Force
+       enable, force := routerConfig.Enabled, routerConfig.Force
        if !enable {
                return nil, false, false, nil
        }
 
-       conditionRouters := make([]*StateRouter, 0, 
len(routerConfig.Conditions))
+       conditionRouters := make([]*MultiDestRouter, 0, 
len(routerConfig.Conditions))
        for _, conditionRule := range routerConfig.Conditions {
                url, err := common.NewURL("condition://")
                if err != nil {
                        return nil, false, false, err
                }
-               url.AddParam(constant.RuleKey, conditionRule.Rule)
+
+               url.SetAttribute(constant.RuleKey, conditionRule)
+               url.AddParam(constant.TrafficDisableKey, 
strconv.FormatBool(conditionRule.Disable))
                url.AddParam(constant.ForceKey, 
strconv.FormatBool(conditionRule.Force))
-               url.AddParam(constant.PriorityKey, 
strconv.FormatInt(int64(conditionRule.Priority), 10))
-               conditionRoute, err := NewConditionStateRouter(url)
+               if conditionRule.Priority < 0 {
+                       logger.Warnf("got 
conditionRouteConfig.conditions.priority (%d < 0) is invalid, ignore priority 
value, use defatult %d ", conditionRule.Priority, constant.DefaultRoutePriority)
+               } else {
+                       url.AddParam(constant.PriorityKey, 
strconv.FormatInt(int64(conditionRule.Priority), 10))
+               }
+               if conditionRule.Ratio < 0 || conditionRule.Ratio > 100 {
+                       logger.Warnf("got conditionRouteConfig.conditions.ratio 
(%d) is invalid, hope (0 - 100), ignore ratio value, use defatult %d ", 
conditionRule.Ratio, constant.DefaultRouteRatio)
+               } else {
+                       url.AddParam(constant.RatioKey, 
strconv.FormatInt(int64(conditionRule.Ratio), 10))
+               }
+
+               conditionRoute, err := NewConditionMultiDestRouter(url)
                if err != nil {
                        return nil, false, false, err
                }
@@ -203,7 +218,7 @@ func generateMultiConditionRoute(rawConfig string) 
(multiplyConditionRoute, bool
        return conditionRouters, force, enable, nil
 }
 
-func generateConditionsRoute(rawConfig string) (conditionRoute, bool, bool, 
error) {
+func generateConditionsRoute(rawConfig string) (stateRouters, bool, bool, 
error) {
        routerConfig, err := parseConditionRoute(rawConfig)
        if err != nil {
                logger.Warnf("[condition router]Build a new condition route 
config error, %s and we will use the original condition rule configuration.", 
err.Error())
diff --git a/cluster/router/condition/route.go 
b/cluster/router/condition/route.go
index 7d3074af2..55e85bdfd 100644
--- a/cluster/router/condition/route.go
+++ b/cluster/router/condition/route.go
@@ -18,6 +18,7 @@
 package condition
 
 import (
+       "math/rand"
        "regexp"
        "sort"
        "strings"
@@ -48,9 +49,6 @@ var (
 )
 
 type StateRouter struct {
-       priority      int64
-       force         bool
-       url           *common.URL
        whenCondition map[string]matcher.Matcher
        thenCondition map[string]matcher.Matcher
 }
@@ -62,13 +60,7 @@ func NewConditionStateRouter(url *common.URL) (*StateRouter, 
error) {
                return nil, errors.Errorf("No ConditionMatcherFactory exists")
        }
 
-       force := url.GetParamBool(constant.ForceKey, false)
-       priority := url.GetParamInt(constant.PriorityKey, 
constant.DefaultPriority)
-       c := &StateRouter{
-               url:      url,
-               force:    force,
-               priority: priority,
-       }
+       c := &StateRouter{}
 
        when, then, err := generateMatcher(url)
        if err != nil {
@@ -83,18 +75,18 @@ func NewConditionStateRouter(url *common.URL) 
(*StateRouter, error) {
 // condition rule like `self_condition => peers_condition `
 //
 // @return active_peers_invokers, Is_self_condition_match_success
-func (s *StateRouter) Route(invokers []protocol.Invoker, url *common.URL, 
invocation protocol.Invocation) ([]protocol.Invoker, bool) {
+func (s *StateRouter) Route(invokers []protocol.Invoker, url *common.URL, 
invocation protocol.Invocation) []protocol.Invoker {
        if len(invokers) == 0 {
-               return invokers, false
+               return invokers
        }
 
        if !s.matchWhen(url, invocation) {
-               return invokers, false
+               return invokers
        }
 
        if len(s.thenCondition) == 0 {
                logger.Warn("condition state router thenCondition is empty")
-               return []protocol.Invoker{}, true
+               return []protocol.Invoker{}
        }
 
        var result = make([]protocol.Invoker, 0, len(invokers))
@@ -104,7 +96,7 @@ func (s *StateRouter) Route(invokers []protocol.Invoker, url 
*common.URL, invoca
                }
        }
 
-       return result, true
+       return result
 }
 
 func (s *StateRouter) matchWhen(url *common.URL, invocation 
protocol.Invocation) bool {
@@ -307,6 +299,156 @@ func parseConditionRoute(routeContent string) 
(*config.RouterConfig, error) {
        return routerConfig, nil
 }
 
+// MultiDestRouter Multiply-Destination-Router
+type MultiDestRouter struct {
+       whenCondition  map[string]matcher.Matcher
+       trafficDisable bool
+       thenCondition  []condSet
+       ratio          int
+       priority       int
+       force          bool
+}
+
+type condSet struct {
+       cond         map[string]matcher.Matcher
+       subSetWeight int
+}
+
+func newCondSet(cond map[string]matcher.Matcher, subSetWeight int) *condSet {
+       if subSetWeight <= 0 {
+               subSetWeight = constant.DefaultRouteConditionSubSetWeight
+       }
+       return &condSet{cond: cond, subSetWeight: subSetWeight}
+}
+
+type destSets struct {
+       dest []struct {
+               weight int
+               ivks   []protocol.Invoker
+       }
+       weightSum int
+}
+
+func newDestSets() *destSets {
+       return &destSets{
+               dest: make([]struct {
+                       weight int
+                       ivks   []protocol.Invoker
+               }, 0),
+               weightSum: 0,
+       }
+}
+
+func (s *destSets) addDest(weight int, ivks []protocol.Invoker) {
+       s.dest = append(s.dest, struct {
+               weight int
+               ivks   []protocol.Invoker
+       }{weight: weight, ivks: ivks})
+       s.weightSum += weight
+}
+
+func (s *destSets) randDest() []protocol.Invoker {
+       if len(s.dest) == 1 {
+               return s.dest[0].ivks
+       }
+       sum := rand.Intn(s.weightSum)
+       for _, d := range s.dest {
+               sum -= d.weight
+               if sum <= 0 {
+                       return d.ivks
+               }
+       }
+       return nil
+}
+
+func (m MultiDestRouter) Route(invokers []protocol.Invoker, url *common.URL, 
invocation protocol.Invocation) ([]protocol.Invoker, bool) {
+       if len(invokers) == 0 {
+               return invokers, false
+       }
+
+       if !doMatch(url, nil, invocation, m.whenCondition, true) {
+               return invokers, false
+       }
+
+       if m.trafficDisable {
+               invocation.SetAttachment(constant.TrafficDisableKey, struct{}{})
+               return []protocol.Invoker{}, true
+       }
+
+       if len(m.thenCondition) == 0 {
+               logger.Warn("condition state router thenCondition is empty")
+               return []protocol.Invoker{}, true
+       }
+
+       destinations := newDestSets()
+       for _, condition := range m.thenCondition {
+               res := make([]protocol.Invoker, 0)
+               for _, invoker := range invokers {
+                       if doMatch(invoker.GetURL(), url, nil, condition.cond, 
false) {
+                               res = append(res, invoker)
+                       }
+               }
+               if len(res) != 0 {
+                       destinations.addDest(condition.subSetWeight, res)
+               }
+       }
+
+       if len(destinations.dest) != 0 {
+               res := destinations.randDest()
+               // check x% > m.ratio%
+               if len(res)*100/len(invokers) > m.ratio {
+                       return res, true
+               }
+       }
+
+       return []protocol.Invoker{}, true
+}
+
+func NewConditionMultiDestRouter(url *common.URL) (*MultiDestRouter, error) {
+       once.Do(initMatcherFactories)
+
+       if len(matcherFactories) == 0 {
+               return nil, errors.Errorf("No ConditionMatcherFactory exists")
+       }
+
+       rawCondConf, ok := url.GetAttribute(constant.RuleKey)
+       if !ok {
+               return nil, errors.Errorf("Condition Router can't get the rule 
key")
+       }
+       condConf, ok := rawCondConf.(config.ConditionRule)
+       if !ok {
+               return nil, errors.Errorf("Condition Router get the rule key 
invaild , got %T", rawCondConf)
+       }
+
+       c := &MultiDestRouter{
+               whenCondition:  make(map[string]matcher.Matcher),
+               thenCondition:  make([]condSet, 0, len(condConf.To)),
+               trafficDisable: url.GetParamBool(constant.TrafficDisableKey, 
false),
+               ratio:          int(url.GetParamInt32(constant.RatioKey, 
constant.DefaultRouteRatio)),
+               priority:       int(url.GetParamInt32(constant.PriorityKey, 
constant.DefaultRoutePriority)),
+               force:          url.GetParamBool(constant.ForceKey, false),
+       }
+
+       m, err := parseRule(condConf.From.Match)
+       if err != nil {
+               return nil, err
+       }
+       for k, v := range m {
+               // if key same, cover
+               c.whenCondition[k] = v
+       }
+
+       for _, ruleTo := range condConf.To {
+               cond, err := parseRule(ruleTo.Match)
+               if err != nil {
+                       return nil, err
+               }
+               c.thenCondition = append(c.thenCondition, *newCondSet(cond, 
ruleTo.Weight))
+       }
+
+       return c, nil
+}
+
 func parseMultiConditionRoute(routeContent string) (*config.ConditionRouter, 
error) {
        routeDecoder := yaml.NewDecoder(strings.NewReader(routeContent))
        routerConfig := &config.ConditionRouter{}
diff --git a/cluster/router/condition/router_test.go 
b/cluster/router/condition/router_test.go
index d8de7c374..fe0b66954 100644
--- a/cluster/router/condition/router_test.go
+++ b/cluster/router/condition/router_test.go
@@ -214,7 +214,7 @@ func TestRouteMatchFilter(t *testing.T) {
                        router, err := NewConditionStateRouter(url)
                        assert.Nil(t, err)
 
-                       filteredInvokers, _ := router.Route(invokerList, 
data.comsumerURL, rpcInvocation)
+                       filteredInvokers := router.Route(invokerList, 
data.comsumerURL, rpcInvocation)
                        resVal := len(filteredInvokers)
                        assert.Equal(t, data.wantVal, resVal)
                })
@@ -407,7 +407,7 @@ func TestRouteReturn(t *testing.T) {
                        router, err := NewConditionStateRouter(url)
                        assert.Nil(t, err)
 
-                       filterInvokers, _ := router.Route(invokers, 
consumerURL, rpcInvocation)
+                       filterInvokers := router.Route(invokers, consumerURL, 
rpcInvocation)
                        resVal := len(filterInvokers)
 
                        assert.Equal(t, data.wantVal, resVal)
@@ -479,7 +479,7 @@ func TestRouteArguments(t *testing.T) {
 
                        rpcInvocation := invocation.NewRPCInvocation("getBar", 
arguments, nil)
 
-                       filterInvokers, _ := router.Route(invokerList, 
consumerURL, rpcInvocation)
+                       filterInvokers := router.Route(invokerList, 
consumerURL, rpcInvocation)
                        resVal := len(filterInvokers)
                        assert.Equal(t, data.wantVal, resVal)
 
@@ -559,7 +559,7 @@ func TestRouteAttachments(t *testing.T) {
                        router, err := NewConditionStateRouter(url)
                        assert.Nil(t, err)
 
-                       filterInvokers, _ := router.Route(invokerList, 
consumerURL, rpcInvocation)
+                       filterInvokers := router.Route(invokerList, 
consumerURL, rpcInvocation)
 
                        resVal := len(filterInvokers)
                        assert.Equal(t, data.wantVal, resVal)
@@ -648,7 +648,7 @@ func TestRouteRangePattern(t *testing.T) {
                        router, err := NewConditionStateRouter(url)
                        assert.Nil(t, err)
 
-                       filterInvokers, _ := router.Route(invokerList, 
consumerURL, rpcInvocation)
+                       filterInvokers := router.Route(invokerList, 
consumerURL, rpcInvocation)
 
                        resVal := len(filterInvokers)
                        assert.Equal(t, data.wantVal, resVal)
@@ -712,7 +712,7 @@ func TestRouteMultipleConditions(t *testing.T) {
 
                        rpcInvocation := invocation.NewRPCInvocation(method, 
arguments, nil)
 
-                       filterInvokers, _ := router.Route(invokerList, 
consumerUrl, rpcInvocation)
+                       filterInvokers := router.Route(invokerList, 
consumerUrl, rpcInvocation)
                        resVal := len(filterInvokers)
                        assert.Equal(t, data.wantVal, resVal)
                })
@@ -867,68 +867,77 @@ func buildInvokers() []protocol.Invoker {
 func TestConditionRoutePriority(t *testing.T) {
        ivks := buildInvokers()
        ar := NewApplicationRouter()
-       ar.Process(&config_center.ConfigChangeEvent{Key: "", Value: `
-configVersion: v3.1
+       ar.Process(&config_center.ConfigChangeEvent{Key: "", Value: 
`configVersion: v3.1
 scope: service
-force: true
+force: false
 runtime: true
 enabled: true
-key: org.apache.dubbo.samples.CommentService
-conditionAction : true 
+key: shop
 conditions:
-  - rule: method=getComment & env=gray => region=Hangzhou & env=gray
-    priority: 3
-  - rule: method=getComment & env=gray => region=beijing & env=gray
-    priority: 3
-  - rule: method=getComment & env=gray => region=$region & env=gray 
-    priority: 3
-  - rule: method=getComment & env=normal => region=beijing 
-    priority: 3
-  - rule: method=getComment => region=$region ######### match here
-    priority: 30
-  - rule: method=echo => region=$region
-  - rule: method=echo =>
-    force: true
+  - from:
+      match:
+    to:
+      - match: region=$region & version=v1
+      - match: region=$region & version=v2
+        weight: 200
+      - match: region=$region & version=v3
+        weight: 300
+    force: false
+    ratio: 20
+    priority: 20
+  - from: 
+      match:
+        region=beijing & version=v1
+    to:
+      - match: env=$env & region=beijing
+    force: false
+    priority: 100
 `, ConfigType: remoting.EventTypeUpdate})
-       consumerUrl, err := 
common.NewURL("consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing")
+       consumerUrl, err := 
common.NewURL("consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing&version=v1")
        if err != nil {
                panic(err)
        }
        got := ar.Route(ivks, consumerUrl, 
invocation.NewRPCInvocation("getComment", nil, nil))
        expLen := 0
        for _, ivk := range ivks {
-               if ivk.GetURL().GetParam("region", "") == "beijing" {
+               if ivk.GetURL().GetParam("region", "") == "beijing" && "gray" 
== ivk.GetURL().GetParam("env", "") {
                        expLen++
                }
        }
+       if len(ivks)*100/expLen <= 20 {
+               expLen = 0
+       }
        assert.Equal(t, expLen, len(got))
 }
 
 func TestConditionRouteTrafficDisable(t *testing.T) {
        ivks := buildInvokers()
        ar := NewApplicationRouter()
-       ar.Process(&config_center.ConfigChangeEvent{Key: "", Value: `
-configVersion: v3.1
+       ar.Process(&config_center.ConfigChangeEvent{Key: "", Value: 
`configVersion: v3.1
 scope: service
 force: true
 runtime: true
 enabled: true
-key: org.apache.dubbo.samples.CommentService
-conditionAction : true 
+key: shop
 conditions:
-  - rule: method=getComment & env=gray => region=Hangzhou & env=gray
-    priority: 3
-  - rule: method=getComment & env=gray => region=beijing & env=gray
-    priority: 3
-  - rule: method=getComment & env=gray => region=$region & env=gray 
-    priority: 3
-  - rule: method=getComment & env=normal => region=beijing 
-    priority: 3
-  - rule: method=getComment => region=$region 
-    priority: 30
-  - rule: method=echo =>
+  - from:
+      match:
+    to:
+      - match: region=$region & version=v1
+      - match: region=$region & version=v2
+        weight: 200
+      - match: region=$region & version=v3
+        weight: 300
+    force: false
+    ratio: 20
+    priority: 20
+  - from: 
+      match:
+        region=beijing & version=v1
+    to:
     force: true
-  - rule: method=echo => region=$region 
+    ratio: 20 
+    priority: 100
 `, ConfigType: remoting.EventTypeUpdate})
        consumerUrl, err := 
common.NewURL("consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing")
        if err != nil {
@@ -941,23 +950,17 @@ conditions:
 func TestConditionRouteRegionPriority(t *testing.T) {
        ivks := buildInvokers()
        ar := NewApplicationRouter()
-       ar.Process(&config_center.ConfigChangeEvent{Key: "", Value: `
-configVersion: v3.1
+       ar.Process(&config_center.ConfigChangeEvent{Key: "", Value: 
`configVersion: v3.1
 scope: service
 force: true
 runtime: true
 enabled: true
-key: org.apache.dubbo.samples.CommentService
-conditionAction : true 
+key: shop
 conditions:
-  - rule: => region=$region & env=$env
-  - rule: method=getComment & env=gray => env=$env
-  - rule: method=getComment & env=gray & region=beijing => region=beijing & 
env=gray
-  - rule: method=getComment & env=gray => region=$region & env=gray 
-  - rule: method=getComment & env=normal => region=beijing 
-  - rule: method=echo =>
-    force: true
-  - rule: method=echo => region=$region 
+  - from:
+      match:
+    to:
+      - match: region=$region & env=$env
 `, ConfigType: remoting.EventTypeUpdate})
        consumerUrl, err := 
common.NewURL("consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing")
        if err != nil {
@@ -992,33 +995,88 @@ conditions:
        got = ar.Route(ivks, consumerUrl, 
invocation.NewRPCInvocation("getComment", nil, nil))
        expLen = 0
        for _, ivk := range ivks {
-               if ivk.GetURL().GetRawParam("region") == "beijing" {
+               if ivk.GetURL().GetRawParam("region") == 
consumerUrl.GetRawParam("region") &&
+                       ivk.GetURL().GetRawParam("env") == 
consumerUrl.GetRawParam("env") {
                        expLen++
                }
        }
        assert.Equal(t, expLen, len(got))
 }
 
+func TestConditionRouteRegionPriorityFail(t *testing.T) {
+       ivks := buildInvokers()
+       ar := NewApplicationRouter()
+       ar.Process(&config_center.ConfigChangeEvent{Key: "", Value: 
`configVersion: v3.1
+scope: service
+force: true
+runtime: true
+enabled: true
+key: shop
+conditions:
+  - from:
+      match:
+    to:
+      - match: region=$region & env=$env
+    ratio: 100
+`, ConfigType: remoting.EventTypeUpdate})
+       consumerUrl, err := 
common.NewURL("consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing")
+       if err != nil {
+               panic(err)
+       }
+       got := ar.Route(ivks, consumerUrl, 
invocation.NewRPCInvocation("getComment", nil, nil))
+       assert.Equal(t, 0, len(got))
+}
+
 func TestConditionRouteMatchFail(t *testing.T) {
        ivks := buildInvokers()
        ar := NewApplicationRouter()
-       ar.Process(&config_center.ConfigChangeEvent{Key: "", Value: `
-configVersion: v3.1
+       ar.Process(&config_center.ConfigChangeEvent{Key: "", Value: 
`configVersion: v3.1
 scope: service
 force: false
 runtime: true
 enabled: true
-key: org.apache.dubbo.samples.CommentService
-conditionAction : true 
+key: shop
 conditions:
-  - rule: => region=$region & env=$env & errTag=errTag
-  - rule: method=getComment & env=gray => env=$env
-  - rule: method=getComment & env=gray & region=beijing => region=beijing & 
env=gray
-  - rule: method=getComment & env=gray => region=$region & env=gray 
-  - rule: method=getComment & env=normal => region=beijing 
-  - rule: method=echo =>
+  - from:
+      match:
+    to:
+      - match: region=$region & env=$env & err-tag=Err-tag
+  - from:
+      match:
+    trafficDisable: true
+    to:
+      - match:
+`, ConfigType: remoting.EventTypeUpdate})
+       consumerUrl, err := 
common.NewURL("consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing")
+       if err != nil {
+               panic(err)
+       }
+       got := ar.Route(ivks, consumerUrl, 
invocation.NewRPCInvocation("errMethod", nil, nil))
+       assert.Equal(t, 0, len(got))
+}
+
+func TestConditionRouteBanSpecialTraffic(t *testing.T) {
+       ivks := buildInvokers()
+       ar := NewApplicationRouter()
+       ar.Process(&config_center.ConfigChangeEvent{Key: "", Value: 
`configVersion: v3.1
+scope: service
+force: true
+runtime: true
+enabled: true
+key: shop
+conditions:
+  - from:
+      match: env=gray
+    to:
+      - match: 
+    force: true
+    priority: 100
+  - from:
+      match: 
+    to:
+      - match: 
     force: true
-  - rule: method=echo => region=$region 
+    priority: 100
 `, ConfigType: remoting.EventTypeUpdate})
        consumerUrl, err := 
common.NewURL("consumer://127.0.0.1/com.foo.BarService?env=gray&region=beijing")
        if err != nil {
diff --git a/common/constant/key.go b/common/constant/key.go
index 1e9959947..6ffe0642c 100644
--- a/common/constant/key.go
+++ b/common/constant/key.go
@@ -308,27 +308,32 @@ const (
 
 // Use for router module
 const (
-       ScriptRouterRuleSuffix           = ".script-router"
-       TagRouterRuleSuffix              = ".tag-router"
-       ConditionRouterRuleSuffix        = ".condition-router" // Specify 
condition router suffix
-       MeshRouteSuffix                  = ".MESHAPPRULE"      // Specify mesh 
router suffix
-       ForceUseTag                      = "dubbo.force.tag"   // the tag in 
attachment
-       ForceUseCondition                = "dubbo.force.condition"
-       Tagkey                           = "dubbo.tag" // key of tag
-       ConditionKey                     = "dubbo.condition"
-       AttachmentKey                    = DubboCtxKey("attachment") // key in 
context in invoker
-       TagRouterFactoryKey              = "tag"
-       ConditionAppRouterFactoryKey     = "provider.condition"
-       ConditionServiceRouterFactoryKey = "service.condition"
-       ScriptRouterFactoryKey           = "consumer.script"
-       ForceKey                         = "force"
-       PriorityKey                      = "priority"
-       Arguments                        = "arguments"
-       Attachments                      = "attachments"
-       Param                            = "param"
-       Scope                            = "scope"
-       Wildcard                         = "wildcard"
-       MeshRouterFactoryKey             = "mesh"
+       ScriptRouterRuleSuffix            = ".script-router"
+       TagRouterRuleSuffix               = ".tag-router"
+       ConditionRouterRuleSuffix         = ".condition-router" // Specify 
condition router suffix
+       MeshRouteSuffix                   = ".MESHAPPRULE"      // Specify mesh 
router suffix
+       ForceUseTag                       = "dubbo.force.tag"   // the tag in 
attachment
+       ForceUseCondition                 = "dubbo.force.condition"
+       Tagkey                            = "dubbo.tag" // key of tag
+       ConditionKey                      = "dubbo.condition"
+       AttachmentKey                     = DubboCtxKey("attachment") // key in 
context in invoker
+       TagRouterFactoryKey               = "tag"
+       ConditionAppRouterFactoryKey      = "provider.condition"
+       ConditionServiceRouterFactoryKey  = "service.condition"
+       ScriptRouterFactoryKey            = "consumer.script"
+       ForceKey                          = "force"
+       TrafficDisableKey                 = "trafficDisable"
+       PriorityKey                       = "priority"
+       RatioKey                          = "RatioKey"
+       Arguments                         = "arguments"
+       Attachments                       = "attachments"
+       Param                             = "param"
+       Scope                             = "scope"
+       Wildcard                          = "wildcard"
+       MeshRouterFactoryKey              = "mesh"
+       DefaultRouteRatio                 = 0
+       DefaultRouteConditionSubSetWeight = 100
+       DefaultRoutePriority              = 0
 )
 
 // Auth filter
diff --git a/config/router_config.go b/config/router_config.go
index 3cfff9cad..e8f155789 100644
--- a/config/router_config.go
+++ b/config/router_config.go
@@ -50,9 +50,21 @@ type Tag struct {
 }
 
 type ConditionRule struct {
-       Rule     string `validate:"required" yaml:"rule" json:"rule,omitempty" 
property:"rule"`
-       Priority int    `default:"0" yaml:"priority" json:"priority,omitempty" 
property:"priority"`
-       Force    bool   `default:"false" yaml:"force" json:"force,omitempty" 
property:"force"`
+       Priority int               `default:"0" yaml:"priority" 
json:"priority,omitempty" property:"priority"`
+       From     ConditionRuleFrom `yaml:"from" json:"from,omitempty" 
property:"from"`
+       Disable  bool              `default:"false" yaml:"trafficDisable" 
json:"trafficDisable,omitempty" property:"trafficDisable"`
+       To       []ConditionRuleTo `yaml:"to" json:"to,omitempty" property:"to"`
+       Ratio    int               `default:"0" yaml:"ratio" 
json:"ratio,omitempty" property:"priority"`
+       Force    bool              `default:"false" yaml:"force" 
json:"force,omitempty" property:"force"`
+}
+
+type ConditionRuleFrom struct {
+       Match string `yaml:"match" json:"match,omitempty" property:"match"`
+}
+
+type ConditionRuleTo struct {
+       Match  string `yaml:"match" json:"match,omitempty" property:"match"`
+       Weight int    `default:"100" yaml:"weight" json:"weight,omitempty" 
property:"weight"`
 }
 
 // ConditionRouter -- when RouteConfigVersion == v3.1, decode by this

Reply via email to