diff --git a/cluster/cluster_impl/available_cluster_invoker_test.go b/cluster/cluster_impl/available_cluster_invoker_test.go index de04db1da4e8e6df12960b1a2ee81b0044379d6f..dc0666d5afa633c86fdfaa48b93a334c19bb0248 100644 --- a/cluster/cluster_impl/available_cluster_invoker_test.go +++ b/cluster/cluster_impl/available_cluster_invoker_test.go @@ -39,7 +39,7 @@ import ( ) var ( - availableUrl, _ = common.NewURL(context.Background(), "dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider") + availableUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider") ) func registerAvailable(t *testing.T, invoker *mock.MockInvoker) protocol.Invoker { diff --git a/cluster/cluster_impl/base_cluster_invoker_test.go b/cluster/cluster_impl/base_cluster_invoker_test.go index d06d3cc23e75cf2227fa22894475f141ffe09a96..49df78c41b3c3cc7dacf92153fc7e4515a0caec0 100644 --- a/cluster/cluster_impl/base_cluster_invoker_test.go +++ b/cluster/cluster_impl/base_cluster_invoker_test.go @@ -18,7 +18,6 @@ package cluster_impl import ( - "context" "fmt" "testing" ) @@ -37,7 +36,7 @@ import ( func Test_StickyNormal(t *testing.T) { invokers := []protocol.Invoker{} for i := 0; i < 10; i++ { - url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) + url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) url.SetParam("sticky", "true") invokers = append(invokers, NewMockInvoker(url, 1)) } @@ -51,7 +50,7 @@ func Test_StickyNormal(t *testing.T) { func Test_StickyNormalWhenError(t *testing.T) { invokers := []protocol.Invoker{} for i := 0; i < 10; i++ { - url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) + url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) url.SetParam("sticky", "true") invokers = append(invokers, NewMockInvoker(url, 1)) } diff --git a/cluster/cluster_impl/broadcast_cluster_invoker_test.go b/cluster/cluster_impl/broadcast_cluster_invoker_test.go index b20d962e2cffb34d0a151488a1bdf63499e4de86..1de5270265a79b4d1d62317730bd06927d939acd 100644 --- a/cluster/cluster_impl/broadcast_cluster_invoker_test.go +++ b/cluster/cluster_impl/broadcast_cluster_invoker_test.go @@ -39,7 +39,7 @@ import ( ) var ( - broadcastUrl, _ = common.NewURL(context.TODO(), "dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider") + broadcastUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider") ) func registerBroadcast(t *testing.T, mockInvokers ...*mock.MockInvoker) protocol.Invoker { diff --git a/cluster/cluster_impl/failback_cluster_test.go b/cluster/cluster_impl/failback_cluster_test.go index 895077922a88abc05416e58459205b449831ac56..4571fccec59a2f995009f57c35b56ec5e1cb3ea6 100644 --- a/cluster/cluster_impl/failback_cluster_test.go +++ b/cluster/cluster_impl/failback_cluster_test.go @@ -41,7 +41,7 @@ import ( ) var ( - failbackUrl, _ = common.NewURL(context.TODO(), "dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider") + failbackUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider") ) // registerFailback register failbackCluster to cluster extension. diff --git a/cluster/cluster_impl/failfast_cluster_test.go b/cluster/cluster_impl/failfast_cluster_test.go index 9585f03b7fa8f45a19c7c47e04dcd57cc1e4bb11..38e258199e05c396e22118337bbdb3ae2b955bd0 100644 --- a/cluster/cluster_impl/failfast_cluster_test.go +++ b/cluster/cluster_impl/failfast_cluster_test.go @@ -39,7 +39,7 @@ import ( ) var ( - failfastUrl, _ = common.NewURL(context.TODO(), "dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider") + failfastUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider") ) // registerFailfast register failfastCluster to cluster extension. diff --git a/cluster/cluster_impl/failover_cluster_test.go b/cluster/cluster_impl/failover_cluster_test.go index 46b7b28e0299b669f5ec48ed024e7aa80c39e3d8..99c584bb583c1d59ece505feafd74ad6e11f6b9a 100644 --- a/cluster/cluster_impl/failover_cluster_test.go +++ b/cluster/cluster_impl/failover_cluster_test.go @@ -39,9 +39,9 @@ import ( "github.com/apache/dubbo-go/protocol/invocation" ) -///////////////////////////// +// /////////////////////////// // mock invoker -///////////////////////////// +// /////////////////////////// type MockInvoker struct { url common.URL @@ -107,7 +107,7 @@ func normalInvoke(t *testing.T, successCount int, urlParam url.Values, invocatio invokers := []protocol.Invoker{} for i := 0; i < 10; i++ { - url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i), common.WithParams(urlParam)) + url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i), common.WithParams(urlParam)) invokers = append(invokers, NewMockInvoker(url, successCount)) } @@ -157,7 +157,7 @@ func Test_FailoverDestroy(t *testing.T) { invokers := []protocol.Invoker{} for i := 0; i < 10; i++ { - url, _ := common.NewURL(context.Background(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) + url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) invokers = append(invokers, NewMockInvoker(url, 1)) } diff --git a/cluster/cluster_impl/failsafe_cluster_test.go b/cluster/cluster_impl/failsafe_cluster_test.go index 234995b8e522124fe9beff0937ca23a63aa63844..2e35de8da91cc78730b6380bf039f0626ca75ec0 100644 --- a/cluster/cluster_impl/failsafe_cluster_test.go +++ b/cluster/cluster_impl/failsafe_cluster_test.go @@ -39,7 +39,7 @@ import ( ) var ( - failsafeUrl, _ = common.NewURL(context.TODO(), "dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider") + failsafeUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider") ) // registerFailsafe register failsafeCluster to cluster extension. diff --git a/cluster/cluster_impl/forking_cluster_test.go b/cluster/cluster_impl/forking_cluster_test.go index d819781eb23631e6b8eef76e5bdf7d7837f43d53..9797ecbd041ae2e09c3d0566f88d08b7246b900f 100644 --- a/cluster/cluster_impl/forking_cluster_test.go +++ b/cluster/cluster_impl/forking_cluster_test.go @@ -42,7 +42,7 @@ import ( ) var ( - forkingUrl, _ = common.NewURL(context.TODO(), "dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider") + forkingUrl, _ = common.NewURL("dubbo://192.168.1.1:20000/com.ikurento.user.UserProvider") ) func registerForking(t *testing.T, mockInvokers ...*mock.MockInvoker) protocol.Invoker { diff --git a/cluster/cluster_impl/registry_aware_cluster_test.go b/cluster/cluster_impl/registry_aware_cluster_test.go index 7f916c1aaa5609beb3d818e08f5b0950c3273e6d..3d0dcc0159839eb0a08aed842ee084449458c645 100644 --- a/cluster/cluster_impl/registry_aware_cluster_test.go +++ b/cluster/cluster_impl/registry_aware_cluster_test.go @@ -39,7 +39,7 @@ func Test_RegAwareInvokeSuccess(t *testing.T) { invokers := []protocol.Invoker{} for i := 0; i < 10; i++ { - url, _ := common.NewURL(context.Background(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) + url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) invokers = append(invokers, NewMockInvoker(url, 1)) } @@ -55,7 +55,7 @@ func TestDestroy(t *testing.T) { invokers := []protocol.Invoker{} for i := 0; i < 10; i++ { - url, _ := common.NewURL(context.Background(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) + url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) invokers = append(invokers, NewMockInvoker(url, 1)) } diff --git a/cluster/directory/static_directory_test.go b/cluster/directory/static_directory_test.go index 3ce772e8a6287aebef3fdad039e2b12be421c4e3..42ef1bcd0b51ce94040b3cbfac37a1f6de686fbb 100644 --- a/cluster/directory/static_directory_test.go +++ b/cluster/directory/static_directory_test.go @@ -18,7 +18,6 @@ package directory import ( - "context" "fmt" "testing" ) @@ -36,7 +35,7 @@ import ( func Test_StaticDirList(t *testing.T) { invokers := []protocol.Invoker{} for i := 0; i < 10; i++ { - url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) + url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) invokers = append(invokers, protocol.NewBaseInvoker(url)) } @@ -47,7 +46,7 @@ func Test_StaticDirList(t *testing.T) { func Test_StaticDirDestroy(t *testing.T) { invokers := []protocol.Invoker{} for i := 0; i < 10; i++ { - url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) + url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) invokers = append(invokers, protocol.NewBaseInvoker(url)) } diff --git a/cluster/loadbalance/consistent_hash_test.go b/cluster/loadbalance/consistent_hash_test.go index 174d5715dd1258d329f40251e76ca47d98791ea9..a44293172c6e2c96bd098a19306f69260b713689 100644 --- a/cluster/loadbalance/consistent_hash_test.go +++ b/cluster/loadbalance/consistent_hash_test.go @@ -18,7 +18,6 @@ package loadbalance import ( - "context" "testing" ) @@ -44,7 +43,7 @@ type consistentHashSelectorSuite struct { func (s *consistentHashSelectorSuite) SetupTest() { var invokers []protocol.Invoker - url, _ := common.NewURL(context.TODO(), + url, _ := common.NewURL( "dubbo://192.168.1.0:20000/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1") invokers = append(invokers, protocol.NewBaseInvoker(url)) s.selector = newConsistentHashSelector(invokers, "echo", 999944) @@ -56,8 +55,8 @@ func (s *consistentHashSelectorSuite) TestToKey() { } func (s *consistentHashSelectorSuite) TestSelectForKey() { - url1, _ := common.NewURL(context.TODO(), "dubbo://192.168.1.0:8080") - url2, _ := common.NewURL(context.TODO(), "dubbo://192.168.1.0:8081") + url1, _ := common.NewURL("dubbo://192.168.1.0:8080") + url2, _ := common.NewURL("dubbo://192.168.1.0:8081") s.selector.virtualInvokers = make(map[uint32]protocol.Invoker) s.selector.virtualInvokers[99874] = protocol.NewBaseInvoker(url1) s.selector.virtualInvokers[9999945] = protocol.NewBaseInvoker(url2) @@ -84,11 +83,11 @@ type consistentHashLoadBalanceSuite struct { func (s *consistentHashLoadBalanceSuite) SetupTest() { var err error - s.url1, err = common.NewURL(context.TODO(), "dubbo://192.168.1.0:8080/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1") + s.url1, err = common.NewURL("dubbo://192.168.1.0:8080/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1") s.NoError(err) - s.url2, err = common.NewURL(context.TODO(), "dubbo://192.168.1.0:8081/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1") + s.url2, err = common.NewURL("dubbo://192.168.1.0:8081/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1") s.NoError(err) - s.url3, err = common.NewURL(context.TODO(), "dubbo://192.168.1.0:8082/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1") + s.url3, err = common.NewURL("dubbo://192.168.1.0:8082/org.apache.demo.HelloService?methods.echo.hash.arguments=0,1") s.NoError(err) s.invoker1 = protocol.NewBaseInvoker(s.url1) diff --git a/cluster/loadbalance/least_active_test.go b/cluster/loadbalance/least_active_test.go index 6bc6985678d7c392ad21b49ec341c3550265f622..54e57e930f17008cf6d767ef47c0e754ac85d8f7 100644 --- a/cluster/loadbalance/least_active_test.go +++ b/cluster/loadbalance/least_active_test.go @@ -18,7 +18,6 @@ package loadbalance import ( - "context" "fmt" "testing" ) @@ -38,13 +37,13 @@ func TestLeastActiveSelect(t *testing.T) { var invokers []protocol.Invoker - url, _ := common.NewURL(context.TODO(), "dubbo://192.168.1.0:20000/org.apache.demo.HelloService") + url, _ := common.NewURL("dubbo://192.168.1.0:20000/org.apache.demo.HelloService") invokers = append(invokers, protocol.NewBaseInvoker(url)) i := loadBalance.Select(invokers, &invocation.RPCInvocation{}) assert.True(t, i.GetUrl().URLEqual(url)) for i := 1; i < 10; i++ { - url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/org.apache.demo.HelloService", i)) + url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/org.apache.demo.HelloService", i)) invokers = append(invokers, protocol.NewBaseInvoker(url)) } loadBalance.Select(invokers, &invocation.RPCInvocation{}) @@ -56,7 +55,7 @@ func TestLeastActiveByWeight(t *testing.T) { var invokers []protocol.Invoker loop := 3 for i := 1; i <= loop; i++ { - url, _ := common.NewURL(context.TODO(), fmt.Sprintf("test%v://192.168.1.%v:20000/org.apache.demo.HelloService?weight=%v", i, i, i)) + url, _ := common.NewURL(fmt.Sprintf("test%v://192.168.1.%v:20000/org.apache.demo.HelloService?weight=%v", i, i, i)) invokers = append(invokers, protocol.NewBaseInvoker(url)) } diff --git a/cluster/loadbalance/random_test.go b/cluster/loadbalance/random_test.go index ffe65d78ac61e5210d23e44c7f802597fed78f96..ff876f4aef8d229e8041594aaaa096f3ad5b1834 100644 --- a/cluster/loadbalance/random_test.go +++ b/cluster/loadbalance/random_test.go @@ -18,7 +18,6 @@ package loadbalance import ( - "context" "fmt" "net/url" "strconv" @@ -42,13 +41,13 @@ func Test_RandomlbSelect(t *testing.T) { invokers := []protocol.Invoker{} - url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", 0)) + url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", 0)) invokers = append(invokers, protocol.NewBaseInvoker(url)) i := randomlb.Select(invokers, &invocation.RPCInvocation{}) assert.True(t, i.GetUrl().URLEqual(url)) for i := 1; i < 10; i++ { - url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) + url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) invokers = append(invokers, protocol.NewBaseInvoker(url)) } randomlb.Select(invokers, &invocation.RPCInvocation{}) @@ -59,13 +58,13 @@ func Test_RandomlbSelectWeight(t *testing.T) { invokers := []protocol.Invoker{} for i := 0; i < 10; i++ { - url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) + url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) invokers = append(invokers, protocol.NewBaseInvoker(url)) } urlParams := url.Values{} urlParams.Set("methods.test."+constant.WEIGHT_KEY, "10000000000000") - urll, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.100:20000/com.ikurento.user.UserProvider"), common.WithParams(urlParams)) + urll, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.100:20000/com.ikurento.user.UserProvider"), common.WithParams(urlParams)) invokers = append(invokers, protocol.NewBaseInvoker(urll)) ivc := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName("test")) @@ -80,7 +79,7 @@ func Test_RandomlbSelectWeight(t *testing.T) { } assert.Condition(t, func() bool { - //really is 0.9999999999999 + // really is 0.9999999999999 return selected/10000 > 0.9 }) } @@ -90,13 +89,13 @@ func Test_RandomlbSelectWarmup(t *testing.T) { invokers := []protocol.Invoker{} for i := 0; i < 10; i++ { - url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) + url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/com.ikurento.user.UserProvider", i)) invokers = append(invokers, protocol.NewBaseInvoker(url)) } urlParams := url.Values{} urlParams.Set(constant.REMOTE_TIMESTAMP_KEY, strconv.FormatInt(time.Now().Add(time.Minute*(-9)).Unix(), 10)) - urll, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.100:20000/com.ikurento.user.UserProvider"), common.WithParams(urlParams)) + urll, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.100:20000/com.ikurento.user.UserProvider"), common.WithParams(urlParams)) invokers = append(invokers, protocol.NewBaseInvoker(urll)) ivc := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName("test")) diff --git a/cluster/loadbalance/round_robin_test.go b/cluster/loadbalance/round_robin_test.go index 0b8e89c7349afb056309b5a70d91aa5cce309aa0..1517f2a20b473af57cc23e61b988aa5a6a04de31 100644 --- a/cluster/loadbalance/round_robin_test.go +++ b/cluster/loadbalance/round_robin_test.go @@ -18,7 +18,6 @@ package loadbalance import ( - "context" "fmt" "strconv" "testing" @@ -39,13 +38,13 @@ func TestRoundRobinSelect(t *testing.T) { var invokers []protocol.Invoker - url, _ := common.NewURL(context.TODO(), "dubbo://192.168.1.0:20000/org.apache.demo.HelloService") + url, _ := common.NewURL("dubbo://192.168.1.0:20000/org.apache.demo.HelloService") invokers = append(invokers, protocol.NewBaseInvoker(url)) i := loadBalance.Select(invokers, &invocation.RPCInvocation{}) assert.True(t, i.GetUrl().URLEqual(url)) for i := 1; i < 10; i++ { - url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/org.apache.demo.HelloService", i)) + url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/org.apache.demo.HelloService", i)) invokers = append(invokers, protocol.NewBaseInvoker(url)) } loadBalance.Select(invokers, &invocation.RPCInvocation{}) @@ -57,7 +56,7 @@ func TestRoundRobinByWeight(t *testing.T) { var invokers []protocol.Invoker loop := 10 for i := 1; i <= loop; i++ { - url, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://192.168.1.%v:20000/org.apache.demo.HelloService?weight=%v", i, i)) + url, _ := common.NewURL(fmt.Sprintf("dubbo://192.168.1.%v:20000/org.apache.demo.HelloService?weight=%v", i, i)) invokers = append(invokers, protocol.NewBaseInvoker(url)) } diff --git a/cluster/router/condition_router_test.go b/cluster/router/condition_router_test.go index 43e74317e3e07caff4a6e7021352ca417e66ccfb..fc639b9fc77b3b83d01c663fa02a7185a2d03756 100644 --- a/cluster/router/condition_router_test.go +++ b/cluster/router/condition_router_test.go @@ -59,21 +59,21 @@ func (bi *MockInvoker) GetUrl() common.URL { } func getRouteUrl(rule string) *common.URL { - url, _ := common.NewURL(context.TODO(), "condition://0.0.0.0/com.foo.BarService") + url, _ := common.NewURL("condition://0.0.0.0/com.foo.BarService") url.AddParam("rule", rule) url.AddParam("force", "true") return &url } func getRouteUrlWithForce(rule, force string) *common.URL { - url, _ := common.NewURL(context.TODO(), "condition://0.0.0.0/com.foo.BarService") + url, _ := common.NewURL("condition://0.0.0.0/com.foo.BarService") url.AddParam("rule", rule) url.AddParam("force", force) return &url } func getRouteUrlWithNoForce(rule string) *common.URL { - url, _ := common.NewURL(context.TODO(), "condition://0.0.0.0/com.foo.BarService") + url, _ := common.NewURL("condition://0.0.0.0/com.foo.BarService") url.AddParam("rule", rule) return &url } @@ -120,7 +120,7 @@ func TestRoute_matchWhen(t *testing.T) { inv := &invocation.RPCInvocation{} rule := base64.URLEncoding.EncodeToString([]byte("=> host = 1.2.3.4")) router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule)) - cUrl, _ := common.NewURL(context.TODO(), "consumer://1.1.1.1/com.foo.BarService") + cUrl, _ := common.NewURL("consumer://1.1.1.1/com.foo.BarService") matchWhen, _ := router.(*ConditionRouter).MatchWhen(cUrl, inv) assert.Equal(t, true, matchWhen) rule1 := base64.URLEncoding.EncodeToString([]byte("host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4")) @@ -152,9 +152,9 @@ func TestRoute_matchWhen(t *testing.T) { func TestRoute_matchFilter(t *testing.T) { localIP, _ := gxnet.GetLocalIP() t.Logf("The local ip is %s", localIP) - url1, _ := common.NewURL(context.TODO(), "dubbo://10.20.3.3:20880/com.foo.BarService?default.serialization=fastjson") - url2, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) - url3, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) + url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService?default.serialization=fastjson") + url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) + url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) invokers := []protocol.Invoker{NewMockInvoker(url1, 1), NewMockInvoker(url2, 2), NewMockInvoker(url3, 3)} rule1 := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = 10.20.3.3")) rule2 := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = 10.20.3.* & host != 10.20.3.3")) @@ -168,7 +168,7 @@ func TestRoute_matchFilter(t *testing.T) { router4, _ := NewConditionRouterFactory().Router(getRouteUrl(rule4)) router5, _ := NewConditionRouterFactory().Router(getRouteUrl(rule5)) router6, _ := NewConditionRouterFactory().Router(getRouteUrl(rule6)) - cUrl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService") + cUrl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService") fileredInvokers1 := router1.Route(invokers, cUrl, &invocation.RPCInvocation{}) fileredInvokers2 := router2.Route(invokers, cUrl, &invocation.RPCInvocation{}) fileredInvokers3 := router3.Route(invokers, cUrl, &invocation.RPCInvocation{}) @@ -188,18 +188,18 @@ func TestRoute_methodRoute(t *testing.T) { inv := invocation.NewRPCInvocationWithOptions(invocation.WithMethodName("getFoo"), invocation.WithParameterTypes([]reflect.Type{}), invocation.WithArguments([]interface{}{})) rule := base64.URLEncoding.EncodeToString([]byte("host !=4.4.4.* & host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4")) router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule)) - url, _ := common.NewURL(context.TODO(), "consumer://1.1.1.1/com.foo.BarService?methods=setFoo,getFoo,findFoo") + url, _ := common.NewURL("consumer://1.1.1.1/com.foo.BarService?methods=setFoo,getFoo,findFoo") matchWhen, _ := router.(*ConditionRouter).MatchWhen(url, inv) assert.Equal(t, true, matchWhen) - url1, _ := common.NewURL(context.TODO(), "consumer://1.1.1.1/com.foo.BarService?methods=getFoo") + url1, _ := common.NewURL("consumer://1.1.1.1/com.foo.BarService?methods=getFoo") matchWhen, _ = router.(*ConditionRouter).MatchWhen(url1, inv) assert.Equal(t, true, matchWhen) - url2, _ := common.NewURL(context.TODO(), "consumer://1.1.1.1/com.foo.BarService?methods=getFoo") + url2, _ := common.NewURL("consumer://1.1.1.1/com.foo.BarService?methods=getFoo") rule2 := base64.URLEncoding.EncodeToString([]byte("methods=getFoo & host!=1.1.1.1 => host = 1.2.3.4")) router2, _ := NewConditionRouterFactory().Router(getRouteUrl(rule2)) matchWhen, _ = router2.(*ConditionRouter).MatchWhen(url2, inv) assert.Equal(t, false, matchWhen) - url3, _ := common.NewURL(context.TODO(), "consumer://1.1.1.1/com.foo.BarService?methods=getFoo") + url3, _ := common.NewURL("consumer://1.1.1.1/com.foo.BarService?methods=getFoo") rule3 := base64.URLEncoding.EncodeToString([]byte("methods=getFoo & host=1.1.1.1 => host = 1.2.3.4")) router3, _ := NewConditionRouterFactory().Router(getRouteUrl(rule3)) matchWhen, _ = router3.(*ConditionRouter).MatchWhen(url3, inv) @@ -208,12 +208,12 @@ func TestRoute_methodRoute(t *testing.T) { } func TestRoute_ReturnFalse(t *testing.T) { - url, _ := common.NewURL(context.TODO(), "") + url, _ := common.NewURL("") localIP, _ := gxnet.GetLocalIP() invokers := []protocol.Invoker{NewMockInvoker(url, 1), NewMockInvoker(url, 2), NewMockInvoker(url, 3)} inv := &invocation.RPCInvocation{} rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => false")) - curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService") + curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService") router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule)) fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv) assert.Equal(t, 0, len(fileredInvokers)) @@ -221,11 +221,11 @@ func TestRoute_ReturnFalse(t *testing.T) { func TestRoute_ReturnEmpty(t *testing.T) { localIP, _ := gxnet.GetLocalIP() - url, _ := common.NewURL(context.TODO(), "") + url, _ := common.NewURL("") invokers := []protocol.Invoker{NewMockInvoker(url, 1), NewMockInvoker(url, 2), NewMockInvoker(url, 3)} inv := &invocation.RPCInvocation{} rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => ")) - curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService") + curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService") router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule)) fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv) assert.Equal(t, 0, len(fileredInvokers)) @@ -236,7 +236,7 @@ func TestRoute_ReturnAll(t *testing.T) { invokers := []protocol.Invoker{&MockInvoker{}, &MockInvoker{}, &MockInvoker{}} inv := &invocation.RPCInvocation{} rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = " + localIP)) - curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService") + curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService") router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule)) fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv) assert.Equal(t, invokers, fileredInvokers) @@ -244,16 +244,16 @@ func TestRoute_ReturnAll(t *testing.T) { func TestRoute_HostFilter(t *testing.T) { localIP, _ := gxnet.GetLocalIP() - url1, _ := common.NewURL(context.TODO(), "dubbo://10.20.3.3:20880/com.foo.BarService") - url2, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) - url3, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) + url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService") + url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) + url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) invoker1 := NewMockInvoker(url1, 1) invoker2 := NewMockInvoker(url2, 2) invoker3 := NewMockInvoker(url3, 3) invokers := []protocol.Invoker{invoker1, invoker2, invoker3} inv := &invocation.RPCInvocation{} rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = " + localIP)) - curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService") + curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService") router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule)) fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv) assert.Equal(t, 2, len(fileredInvokers)) @@ -263,16 +263,16 @@ func TestRoute_HostFilter(t *testing.T) { func TestRoute_Empty_HostFilter(t *testing.T) { localIP, _ := gxnet.GetLocalIP() - url1, _ := common.NewURL(context.TODO(), "dubbo://10.20.3.3:20880/com.foo.BarService") - url2, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) - url3, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) + url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService") + url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) + url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) invoker1 := NewMockInvoker(url1, 1) invoker2 := NewMockInvoker(url2, 2) invoker3 := NewMockInvoker(url3, 3) invokers := []protocol.Invoker{invoker1, invoker2, invoker3} inv := &invocation.RPCInvocation{} rule := base64.URLEncoding.EncodeToString([]byte(" => " + " host = " + localIP)) - curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService") + curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService") router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule)) fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv) assert.Equal(t, 2, len(fileredInvokers)) @@ -282,16 +282,16 @@ func TestRoute_Empty_HostFilter(t *testing.T) { func TestRoute_False_HostFilter(t *testing.T) { localIP, _ := gxnet.GetLocalIP() - url1, _ := common.NewURL(context.TODO(), "dubbo://10.20.3.3:20880/com.foo.BarService") - url2, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) - url3, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) + url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService") + url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) + url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) invoker1 := NewMockInvoker(url1, 1) invoker2 := NewMockInvoker(url2, 2) invoker3 := NewMockInvoker(url3, 3) invokers := []protocol.Invoker{invoker1, invoker2, invoker3} inv := &invocation.RPCInvocation{} rule := base64.URLEncoding.EncodeToString([]byte("true => " + " host = " + localIP)) - curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService") + curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService") router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule)) fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv) assert.Equal(t, 2, len(fileredInvokers)) @@ -301,16 +301,16 @@ func TestRoute_False_HostFilter(t *testing.T) { func TestRoute_Placeholder(t *testing.T) { localIP, _ := gxnet.GetLocalIP() - url1, _ := common.NewURL(context.TODO(), "dubbo://10.20.3.3:20880/com.foo.BarService") - url2, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) - url3, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) + url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService") + url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) + url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) invoker1 := NewMockInvoker(url1, 1) invoker2 := NewMockInvoker(url2, 2) invoker3 := NewMockInvoker(url3, 3) invokers := []protocol.Invoker{invoker1, invoker2, invoker3} inv := &invocation.RPCInvocation{} rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = $host")) - curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService") + curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService") router, _ := NewConditionRouterFactory().Router(getRouteUrl(rule)) fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv) assert.Equal(t, 2, len(fileredInvokers)) @@ -320,16 +320,16 @@ func TestRoute_Placeholder(t *testing.T) { func TestRoute_NoForce(t *testing.T) { localIP, _ := gxnet.GetLocalIP() - url1, _ := common.NewURL(context.TODO(), "dubbo://10.20.3.3:20880/com.foo.BarService") - url2, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) - url3, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) + url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService") + url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) + url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) invoker1 := NewMockInvoker(url1, 1) invoker2 := NewMockInvoker(url2, 2) invoker3 := NewMockInvoker(url3, 3) invokers := []protocol.Invoker{invoker1, invoker2, invoker3} inv := &invocation.RPCInvocation{} rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = 1.2.3.4")) - curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService") + curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService") router, _ := NewConditionRouterFactory().Router(getRouteUrlWithNoForce(rule)) fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv) assert.Equal(t, invokers, fileredInvokers) @@ -337,16 +337,16 @@ func TestRoute_NoForce(t *testing.T) { func TestRoute_Force(t *testing.T) { localIP, _ := gxnet.GetLocalIP() - url1, _ := common.NewURL(context.TODO(), "dubbo://10.20.3.3:20880/com.foo.BarService") - url2, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) - url3, _ := common.NewURL(context.TODO(), fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) + url1, _ := common.NewURL("dubbo://10.20.3.3:20880/com.foo.BarService") + url2, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) + url3, _ := common.NewURL(fmt.Sprintf("dubbo://%s:20880/com.foo.BarService", localIP)) invoker1 := NewMockInvoker(url1, 1) invoker2 := NewMockInvoker(url2, 2) invoker3 := NewMockInvoker(url3, 3) invokers := []protocol.Invoker{invoker1, invoker2, invoker3} inv := &invocation.RPCInvocation{} rule := base64.URLEncoding.EncodeToString([]byte("host = " + localIP + " => " + " host = 1.2.3.4")) - curl, _ := common.NewURL(context.TODO(), "consumer://"+localIP+"/com.foo.BarService") + curl, _ := common.NewURL("consumer://" + localIP + "/com.foo.BarService") router, _ := NewConditionRouterFactory().Router(getRouteUrlWithForce(rule, "true")) fileredInvokers := router.(*ConditionRouter).Route(invokers, curl, inv) assert.Equal(t, 0, len(fileredInvokers)) diff --git a/common/constant/key.go b/common/constant/key.go index d201570b9ad5415694af5598fba7983289b2b295..eff704371c7c5b66ca11a846ad7603a01f8b5708 100644 --- a/common/constant/key.go +++ b/common/constant/key.go @@ -141,3 +141,21 @@ const ( const ( TRACING_REMOTE_SPAN_CTX = "tracing.remote.span.ctx" ) + +const ( + CONSUMER_SIGN_FILTER = "sign" + PROVIDER_AUTH_FILTER = "auth" + SERVICE_AUTH_KEY = "auth" + AUTHENTICATOR_KEY = "authenticator" + DEFAULT_AUTHENTICATOR = "accesskeys" + DEFAULT_ACCESS_KEY_STORAGE = "urlstorage" + ACCESS_KEY_STORAGE_KEY = "accessKey.storage" + REQUEST_TIMESTAMP_KEY = "timestamp" + REQUEST_SIGNATURE_KEY = "signature" + AK_KEY = "ak" + SIGNATURE_STRING_FORMAT = "%s#%s#%s#%s" + PARAMTER_SIGNATURE_ENABLE_KEY = "param.sign" + CONSUMER = "consumer" + ACCESS_KEY_ID_KEY = "accessKeyId" + SECRET_ACCESS_KEY_KEY = "secretAccessKey" +) diff --git a/common/constant/time.go b/common/constant/time.go new file mode 100644 index 0000000000000000000000000000000000000000..be1baaca67f474aa92e86e529d03400948ef4612 --- /dev/null +++ b/common/constant/time.go @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package constant + +import ( + "time" +) + +var ( + MsToNanoRate = int64(time.Millisecond / time.Nanosecond) +) diff --git a/common/extension/auth.go b/common/extension/auth.go new file mode 100644 index 0000000000000000000000000000000000000000..e57e22f660b6d4dec63f8b4a06c25b05bd5c8d72 --- /dev/null +++ b/common/extension/auth.go @@ -0,0 +1,32 @@ +package extension + +import ( + "github.com/apache/dubbo-go/filter" +) + +var ( + authenticators = make(map[string]func() filter.Authenticator) + accesskeyStorages = make(map[string]func() filter.AccessKeyStorage) +) + +func SetAuthenticator(name string, fcn func() filter.Authenticator) { + authenticators[name] = fcn +} + +func GetAuthenticator(name string) filter.Authenticator { + if authenticators[name] == nil { + panic("authenticator for " + name + " is not existing, make sure you have import the package.") + } + return authenticators[name]() +} + +func SetAccesskeyStorages(name string, fcn func() filter.AccessKeyStorage) { + accesskeyStorages[name] = fcn +} + +func GetAccesskeyStorages(name string) filter.AccessKeyStorage { + if accesskeyStorages[name] == nil { + panic("accesskeyStorages for " + name + " is not existing, make sure you have import the package.") + } + return accesskeyStorages[name]() +} diff --git a/common/extension/metrics.go b/common/extension/metrics.go new file mode 100644 index 0000000000000000000000000000000000000000..42fca7a2db36614fcef31dd5ba7324a156164d4f --- /dev/null +++ b/common/extension/metrics.go @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package extension + +import ( + "github.com/apache/dubbo-go/metrics" +) + +var ( + // we couldn't store the instance because the some instance may initialize before loading configuration + // so lazy initialization will be better. + metricReporterMap = make(map[string]func() metrics.Reporter, 4) +) + +// SetMetricReporter set a reporter with the name +func SetMetricReporter(name string, reporterFunc func() metrics.Reporter) { + metricReporterMap[name] = reporterFunc +} + +// GetMetricReporter find the reporter with name. +// if not found, it will panic. +// we should know that this method usually is called when system starts, so we should panic +func GetMetricReporter(name string) metrics.Reporter { + reporterFunc, found := metricReporterMap[name] + if !found { + panic("Cannot find the reporter with name: " + name) + } + return reporterFunc() +} diff --git a/common/extension/metrics_test.go b/common/extension/metrics_test.go new file mode 100644 index 0000000000000000000000000000000000000000..6a8a3fe538a9cd68c57c91592a88ec257ae4a267 --- /dev/null +++ b/common/extension/metrics_test.go @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package extension + +import ( + "context" + "testing" + "time" +) + +import ( + "github.com/stretchr/testify/assert" +) + +import ( + "github.com/apache/dubbo-go/metrics" + "github.com/apache/dubbo-go/protocol" +) + +func TestGetMetricReporter(t *testing.T) { + reporter := &mockReporter{} + name := "mock" + SetMetricReporter(name, func() metrics.Reporter { + return reporter + }) + res := GetMetricReporter(name) + assert.Equal(t, reporter, res) +} + +type mockReporter struct { +} + +func (m mockReporter) Report(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation, cost time.Duration, res protocol.Result) { +} diff --git a/common/url.go b/common/url.go index a073e013f47a2acff4782ffa4444203fa0cec9b5..360f0aa4caa185d8086eb07497176ae627f47d47 100644 --- a/common/url.go +++ b/common/url.go @@ -19,7 +19,6 @@ package common import ( "bytes" - "context" "encoding/base64" "fmt" "math" @@ -85,7 +84,6 @@ type baseUrl struct { paramsLock sync.RWMutex params url.Values PrimitiveURL string - ctx context.Context } // URL ... @@ -194,14 +192,15 @@ func NewURLWithOptions(opts ...option) *URL { return url } -// NewURL ... -func NewURL(ctx context.Context, urlString string, opts ...option) (URL, error) { +// NewURL will create a new url +// the urlString should not be empty +func NewURL(urlString string, opts ...option) (URL, error) { var ( err error rawUrlString string serviceUrl *url.URL - s = URL{baseUrl: baseUrl{ctx: ctx}} + s = URL{baseUrl: baseUrl{}} ) // new a null instance @@ -216,7 +215,7 @@ func NewURL(ctx context.Context, urlString string, opts ...option) (URL, error) //rawUrlString = "//" + rawUrlString if strings.Index(rawUrlString, "//") < 0 { - t := URL{baseUrl: baseUrl{ctx: ctx}} + t := URL{baseUrl: baseUrl{}} for _, opt := range opts { opt(&t) } @@ -339,17 +338,34 @@ func (c URL) ServiceKey() string { return buf.String() } +// ColonSeparatedKey +// The format is "{interface}:[version]:[group]" +func (c *URL) ColonSeparatedKey() string { + intf := c.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/")) + if intf == "" { + return "" + } + buf := &bytes.Buffer{} + buf.WriteString(intf) + buf.WriteString(":") + version := c.GetParam(constant.VERSION_KEY, "") + if version != "" && version != "0.0.0" { + buf.WriteString(version) + } + group := c.GetParam(constant.GROUP_KEY, "") + buf.WriteString(":") + if group != "" { + buf.WriteString(group) + } + return buf.String() +} + // EncodedServiceKey ... func (c *URL) EncodedServiceKey() string { serviceKey := c.ServiceKey() return strings.Replace(serviceKey, "/", "*", 1) } -// Context ... -func (c URL) Context() context.Context { - return c.ctx -} - // Service ... func (c URL) Service() string { service := c.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/")) diff --git a/common/url_test.go b/common/url_test.go index c70c58bc215b6449311d43f9f9cffeb89623f80c..835973065b6d7426e5487fe76602ca27701130a1 100644 --- a/common/url_test.go +++ b/common/url_test.go @@ -18,7 +18,6 @@ package common import ( - "context" "encoding/base64" "net/url" "testing" @@ -56,10 +55,10 @@ func TestNewURLWithOptions(t *testing.T) { } func TestURL(t *testing.T) { - u, err := NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+ - "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+ - "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+ - "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+ + u, err := NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&" + + "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" + + "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" + + "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" + "side=provider&timeout=3000×tamp=1556509797245") assert.NoError(t, err) @@ -83,7 +82,7 @@ func TestURL(t *testing.T) { } func TestURLWithoutSchema(t *testing.T) { - u, err := NewURL(context.TODO(), "127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+ + u, err := NewURL("127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+ "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+ "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+ "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+ @@ -110,13 +109,13 @@ func TestURLWithoutSchema(t *testing.T) { } func TestURL_URLEqual(t *testing.T) { - u1, err := NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0") + u1, err := NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0") assert.NoError(t, err) - u2, err := NewURL(context.TODO(), "dubbo://127.0.0.2:20001/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0") + u2, err := NewURL("dubbo://127.0.0.2:20001/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0") assert.NoError(t, err) assert.True(t, u1.URLEqual(u2)) - u3, err := NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0") + u3, err := NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0") assert.NoError(t, err) assert.False(t, u1.URLEqual(u3)) } @@ -166,7 +165,7 @@ func TestURL_GetParamAndDecoded(t *testing.T) { assert.Equal(t, rule, v) } func TestURL_GetRawParam(t *testing.T) { - u, _ := NewURL(context.TODO(), "condition://0.0.0.0:8080/com.foo.BarService?serialization=fastjson") + u, _ := NewURL("condition://0.0.0.0:8080/com.foo.BarService?serialization=fastjson") u.Username = "test" u.Password = "test" assert.Equal(t, "condition", u.GetRawParam("protocol")) @@ -178,7 +177,7 @@ func TestURL_GetRawParam(t *testing.T) { assert.Equal(t, "fastjson", u.GetRawParam("serialization")) } func TestURL_ToMap(t *testing.T) { - u, _ := NewURL(context.TODO(), "condition://0.0.0.0:8080/com.foo.BarService?serialization=fastjson") + u, _ := NewURL("condition://0.0.0.0:8080/com.foo.BarService?serialization=fastjson") u.Username = "test" u.Password = "test" @@ -240,8 +239,8 @@ func TestMergeUrl(t *testing.T) { serviceUrlParams.Set(constant.CLUSTER_KEY, "roundrobin") serviceUrlParams.Set(constant.RETRIES_KEY, "2") serviceUrlParams.Set(constant.METHOD_KEYS+".testMethod."+constant.RETRIES_KEY, "2") - referenceUrl, _ := NewURL(context.TODO(), "mock1://127.0.0.1:1111", WithParams(referenceUrlParams), WithMethods([]string{"testMethod"})) - serviceUrl, _ := NewURL(context.TODO(), "mock2://127.0.0.1:20000", WithParams(serviceUrlParams)) + referenceUrl, _ := NewURL("mock1://127.0.0.1:1111", WithParams(referenceUrlParams), WithMethods([]string{"testMethod"})) + serviceUrl, _ := NewURL("mock2://127.0.0.1:20000", WithParams(serviceUrlParams)) mergedUrl := MergeUrl(&serviceUrl, &referenceUrl) assert.Equal(t, "random", mergedUrl.GetParam(constant.CLUSTER_KEY, "")) @@ -252,7 +251,7 @@ func TestMergeUrl(t *testing.T) { } func TestURL_SetParams(t *testing.T) { - u1, err := NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&configVersion=1.0") + u1, err := NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&configVersion=1.0") assert.NoError(t, err) params := url.Values{} params.Set("key", "3") @@ -262,7 +261,7 @@ func TestURL_SetParams(t *testing.T) { } func TestClone(t *testing.T) { - u1, err := NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&configVersion=1.0") + u1, err := NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&configVersion=1.0") assert.NoError(t, err) u2 := u1.Clone() assert.Equal(t, u2.Protocol, "dubbo") @@ -271,3 +270,17 @@ func TestClone(t *testing.T) { assert.Equal(t, u1.Protocol, "dubbo") assert.Equal(t, u2.Protocol, "provider") } + +func TestColonSeparatedKey(t *testing.T) { + u1, _ := NewURL("dubbo://127.0.0.1:20000") + u1.AddParam(constant.INTERFACE_KEY, "com.ikurento.user.UserProvider") + + assert.Equal(t, u1.ColonSeparatedKey(), u1.GetParam(constant.INTERFACE_KEY, "")+"::") + u1.AddParam(constant.VERSION_KEY, "version1") + assert.Equal(t, u1.ColonSeparatedKey(), u1.GetParam(constant.INTERFACE_KEY, "")+":version1:") + u1.AddParam(constant.GROUP_KEY, "group1") + assert.Equal(t, u1.ColonSeparatedKey(), u1.GetParam(constant.INTERFACE_KEY, "")+":version1:group1") + u1.SetParam(constant.VERSION_KEY, "") + assert.Equal(t, u1.ColonSeparatedKey(), u1.GetParam(constant.INTERFACE_KEY, "")+"::group1") + +} diff --git a/config/base_config.go b/config/base_config.go index 09495741153cf7caae4bb10ada0aaa686fbf0325..942e966eb31e9570e957ad74aa696aa9ef29c5b0 100644 --- a/config/base_config.go +++ b/config/base_config.go @@ -18,7 +18,6 @@ package config import ( - "context" "reflect" "strconv" "strings" @@ -40,16 +39,21 @@ type multiConfiger interface { Prefix() string } -// BaseConfig ... +// BaseConfig is the common configuration for provider and consumer type BaseConfig struct { ConfigCenterConfig *ConfigCenterConfig `yaml:"config_center" json:"config_center,omitempty"` configCenterUrl *common.URL prefix string fatherConfig interface{} + + MetricConfig *MetricConfig `yaml:"metrics" json:"metrics,omitempty"` } -func (c *BaseConfig) startConfigCenter(ctx context.Context) error { - url, err := common.NewURL(ctx, c.ConfigCenterConfig.Address, common.WithProtocol(c.ConfigCenterConfig.Protocol), common.WithParams(c.ConfigCenterConfig.GetUrlMap())) +// startConfigCenter will start the config center. +// it will prepare the environment +func (c *BaseConfig) startConfigCenter() error { + url, err := common.NewURL(c.ConfigCenterConfig.Address, + common.WithProtocol(c.ConfigCenterConfig.Protocol), common.WithParams(c.ConfigCenterConfig.GetUrlMap())) if err != nil { return err } diff --git a/config/base_config_test.go b/config/base_config_test.go index ab2769578072387e4686593f3c2c10fb8e49731d..d16b2420922ece60ef2135729cd47d5aa73a3760 100644 --- a/config/base_config_test.go +++ b/config/base_config_test.go @@ -17,7 +17,6 @@ package config import ( - "context" "fmt" "reflect" "testing" @@ -492,7 +491,7 @@ func Test_startConfigCenter(t *testing.T) { Group: "dubbo", ConfigFile: "mockDubbo.properties", }} - err := c.startConfigCenter(context.Background()) + err := c.startConfigCenter() assert.NoError(t, err) b, v := config.GetEnvInstance().Configuration().Back().Value.(*config.InmemoryConfiguration).GetProperty("dubbo.application.organization") assert.True(t, b) diff --git a/config/config_loader.go b/config/config_loader.go index d6eb7ff524a53c6949d22a2b34eb965274a75232..875d1f6ddb84434d32296076cd31be96c1385b8a 100644 --- a/config/config_loader.go +++ b/config/config_loader.go @@ -31,9 +31,11 @@ import ( ) var ( - consumerConfig *ConsumerConfig - providerConfig *ProviderConfig - maxWait = 3 + consumerConfig *ConsumerConfig + providerConfig *ProviderConfig + metricConfig *MetricConfig + applicationConfig *ApplicationConfig + maxWait = 3 ) // loaded consumer & provider config from xxx.yml, and log config from xxx.xml @@ -75,6 +77,10 @@ func Load() { if consumerConfig == nil { logger.Warnf("consumerConfig is nil!") } else { + + metricConfig = consumerConfig.MetricConfig + applicationConfig = consumerConfig.ApplicationConfig + checkApplicationName(consumerConfig.ApplicationConfig) if err := configCenterRefreshConsumer(); err != nil { logger.Errorf("[consumer config center refresh] %#v", err) @@ -131,6 +137,11 @@ func Load() { if providerConfig == nil { logger.Warnf("providerConfig is nil!") } else { + + // so, you should know that the consumer's config will be override + metricConfig = providerConfig.MetricConfig + applicationConfig = providerConfig.ApplicationConfig + checkApplicationName(providerConfig.ApplicationConfig) if err := configCenterRefreshProvider(); err != nil { logger.Errorf("[provider config center refresh] %#v", err) @@ -162,3 +173,42 @@ func GetRPCService(name string) common.RPCService { func RPCService(service common.RPCService) { consumerConfig.References[service.Reference()].Implement(service) } + +// GetMetricConfig find the MetricConfig +// if it is nil, create a new one +func GetMetricConfig() *MetricConfig { + if metricConfig == nil { + metricConfig = &MetricConfig{} + } + return metricConfig +} + +// GetApplicationConfig find the application config +// if not, we will create one +// Usually applicationConfig will be initialized when system start +func GetApplicationConfig() *ApplicationConfig { + if applicationConfig == nil { + applicationConfig = &ApplicationConfig{} + } + return applicationConfig +} + +// GetProviderConfig find the provider config +// if not found, create new one +func GetProviderConfig() ProviderConfig { + if providerConfig == nil { + logger.Warnf("providerConfig is nil!") + return ProviderConfig{} + } + return *providerConfig +} + +// GetConsumerConfig find the consumer config +// if not found, create new one +func GetConsumerConfig() ConsumerConfig { + if consumerConfig == nil { + logger.Warnf("consumerConfig is nil!") + return ConsumerConfig{} + } + return *consumerConfig +} diff --git a/config/consumer_config.go b/config/consumer_config.go index 7756f3b51c0f46a19687affb4dc6eadf9ef711c7..98917ebca2ff3abcce6c952a9bc78d93cd74f5d8 100644 --- a/config/consumer_config.go +++ b/config/consumer_config.go @@ -18,7 +18,6 @@ package config import ( - "context" "io/ioutil" "path" "time" @@ -85,15 +84,6 @@ func SetConsumerConfig(c ConsumerConfig) { consumerConfig = &c } -// GetConsumerConfig ... -func GetConsumerConfig() ConsumerConfig { - if consumerConfig == nil { - logger.Warnf("consumerConfig is nil!") - return ConsumerConfig{} - } - return *consumerConfig -} - // ConsumerInit ... func ConsumerInit(confConFile string) error { if confConFile == "" { @@ -145,7 +135,7 @@ func configCenterRefreshConsumer() error { var err error if consumerConfig.ConfigCenterConfig != nil { consumerConfig.SetFatherConfig(consumerConfig) - if err := consumerConfig.startConfigCenter(context.Background()); err != nil { + if err := consumerConfig.startConfigCenter(); err != nil { return perrors.Errorf("start config center error , error message is {%v}", perrors.WithStack(err)) } consumerConfig.fresh() diff --git a/config/metric_config.go b/config/metric_config.go new file mode 100644 index 0000000000000000000000000000000000000000..73a3ca1cfe4f1461db2e225947dd13199b2ad55e --- /dev/null +++ b/config/metric_config.go @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package config + +var ( + defaultHistogramBucket = []float64{10, 50, 100, 200, 500, 1000, 10000} +) + +// This is the config struct for all metrics implementation +type MetricConfig struct { + Reporters []string `yaml:"reporters" json:"reporters,omitempty"` + HistogramBucket []float64 `yaml:"histogram_bucket" json:"histogram_bucket,omitempty"` +} + +// find the histogram bucket +// if it's empty, the default value will be return +func (mc *MetricConfig) GetHistogramBucket() []float64 { + if len(mc.HistogramBucket) == 0 { + mc.HistogramBucket = defaultHistogramBucket + } + return mc.HistogramBucket +} diff --git a/config/metric_config_test.go b/config/metric_config_test.go new file mode 100644 index 0000000000000000000000000000000000000000..fe9d2493f37c0bd563931f5acf133105d72d0e53 --- /dev/null +++ b/config/metric_config_test.go @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package config + +import ( + "testing" +) + +import ( + "github.com/stretchr/testify/assert" +) + +func TestGetMetricConfig(t *testing.T) { + empty := GetMetricConfig() + assert.NotNil(t, empty) +} diff --git a/config/provider_config.go b/config/provider_config.go index 0bfa78647b58d9b6eb961adc5485207faffe1e1e..2967ecad3a49218aecf87be7d8e2f76281bfb1b4 100644 --- a/config/provider_config.go +++ b/config/provider_config.go @@ -18,7 +18,6 @@ package config import ( - "context" "io/ioutil" "path" ) @@ -76,15 +75,6 @@ func SetProviderConfig(p ProviderConfig) { providerConfig = &p } -// GetProviderConfig ... -func GetProviderConfig() ProviderConfig { - if providerConfig == nil { - logger.Warnf("providerConfig is nil!") - return ProviderConfig{} - } - return *providerConfig -} - // ProviderInit ... func ProviderInit(confProFile string) error { if len(confProFile) == 0 { @@ -123,7 +113,7 @@ func configCenterRefreshProvider() error { //fresh it if providerConfig.ConfigCenterConfig != nil { providerConfig.fatherConfig = providerConfig - if err := providerConfig.startConfigCenter(context.Background()); err != nil { + if err := providerConfig.startConfigCenter(); err != nil { return perrors.Errorf("start config center error , error message is {%v}", perrors.WithStack(err)) } providerConfig.fresh() diff --git a/config/reference_config.go b/config/reference_config.go index 07b7e8f125c4a31b668d06bfcea8cb835385fd9a..edfa17a27e88a605b71bc7f6dec1b133bd29abe9 100644 --- a/config/reference_config.go +++ b/config/reference_config.go @@ -105,7 +105,7 @@ func (c *ReferenceConfig) Refer(_ interface{}) { if c.Url != "" { urlStrings := gxstrings.RegSplit(c.Url, "\\s*[;]+\\s*") for _, urlStr := range urlStrings { - serviceUrl, err := common.NewURL(context.Background(), urlStr) + serviceUrl, err := common.NewURL(urlStr) if err != nil { panic(fmt.Sprintf("user specified URL %v refer error, error message is %v ", urlStr, err.Error())) } diff --git a/config/registry_config.go b/config/registry_config.go index c347c2c2348018a66114c56a1c982d57d4f2783f..4e4b6e97d79a9402616b6cac954f7a09b2973dcc 100644 --- a/config/registry_config.go +++ b/config/registry_config.go @@ -18,7 +18,6 @@ package config import ( - "context" "net/url" "strconv" "strings" @@ -95,9 +94,7 @@ func loadRegistries(targetRegistries string, registries map[string]*RegistryConf addresses := strings.Split(registryConf.Address, ",") address := addresses[0] address = traslateRegistryConf(address, registryConf) - url, err = common.NewURL( - context.Background(), - constant.REGISTRY_PROTOCOL+"://"+address, + url, err = common.NewURL(constant.REGISTRY_PROTOCOL+"://"+address, common.WithParams(registryConf.getUrlMap(roleType)), common.WithUsername(registryConf.Username), common.WithPassword(registryConf.Password), diff --git a/config/service_config.go b/config/service_config.go index 37ec3a3ae611d60d71f5679c1d501bb699351849..2111838395d507ebac4f72883c99dd2bb1615850 100644 --- a/config/service_config.go +++ b/config/service_config.go @@ -67,6 +67,8 @@ type ServiceConfig struct { TpsLimitRejectedHandler string `yaml:"tps.limit.rejected.handler" json:"tps.limit.rejected.handler,omitempty" property:"tps.limit.rejected.handler"` ExecuteLimit string `yaml:"execute.limit" json:"execute.limit,omitempty" property:"execute.limit"` ExecuteLimitRejectedHandler string `yaml:"execute.limit.rejected.handler" json:"execute.limit.rejected.handler,omitempty" property:"execute.limit.rejected.handler"` + Auth string `yaml:"auth" json:"auth,omitempty" property:"auth"` + ParamSign string `yaml:"param.sign" json:"param.sign,omitempty" property:"param.sign"` unexported *atomic.Bool exported *atomic.Bool @@ -220,6 +222,10 @@ func (c *ServiceConfig) getUrlMap() url.Values { urlMap.Set(constant.EXECUTE_LIMIT_KEY, c.ExecuteLimit) urlMap.Set(constant.EXECUTE_REJECTED_EXECUTION_HANDLER_KEY, c.ExecuteLimitRejectedHandler) + // auth filter + urlMap.Set(constant.SERVICE_AUTH_KEY, c.Auth) + urlMap.Set(constant.PARAMTER_SIGNATURE_ENABLE_KEY, c.ParamSign) + for _, v := range c.Methods { prefix := "methods." + v.Name + "." urlMap.Set(prefix+constant.LOADBALANCE_KEY, v.Loadbalance) diff --git a/config_center/apollo/impl_test.go b/config_center/apollo/impl_test.go index 84e2b28bac4eace18ec7269249b67c938b96232e..a95524b41b887313993aad4e774ed6d96b24c08f 100644 --- a/config_center/apollo/impl_test.go +++ b/config_center/apollo/impl_test.go @@ -17,7 +17,6 @@ package apollo import ( - "context" "fmt" "net/http" "net/http/httptest" @@ -141,7 +140,7 @@ func serviceConfigResponse(rw http.ResponseWriter, req *http.Request) { fmt.Fprintf(rw, "%s", result) } -//run mock config server +// run mock config server func runMockConfigServer(handlerMap map[string]func(http.ResponseWriter, *http.Request), notifyHandler func(http.ResponseWriter, *http.Request)) *httptest.Server { uriHandlerMap := make(map[string]func(http.ResponseWriter, *http.Request), 0) @@ -196,7 +195,7 @@ func initMockApollo(t *testing.T) *apolloConfiguration { }} apollo := initApollo() apolloUrl := strings.ReplaceAll(apollo.URL, "http", "apollo") - url, err := common.NewURL(context.TODO(), apolloUrl, common.WithParams(c.ConfigCenterConfig.GetUrlMap())) + url, err := common.NewURL(apolloUrl, common.WithParams(c.ConfigCenterConfig.GetUrlMap())) assert.NoError(t, err) configuration, err := newApolloConfiguration(&url) assert.NoError(t, err) @@ -268,7 +267,7 @@ func (l *apolloDataListener) Process(configType *config_center.ConfigChangeEvent } func deleteMockJson(t *testing.T) { - //because the file write in another goroutine,so have a break ... + // because the file write in another goroutine,so have a break ... time.Sleep(100 * time.Millisecond) remove := os.Remove("mockDubbog.properties.json") t.Log("remove result:", remove) diff --git a/config_center/configurator/override_test.go b/config_center/configurator/override_test.go index b8f417b4602e135d114be99637061851088d4e44..329c598efe8ef79d7fc1b79ae182c59b238283ac 100644 --- a/config_center/configurator/override_test.go +++ b/config_center/configurator/override_test.go @@ -17,7 +17,6 @@ package configurator import ( - "context" "testing" ) @@ -32,36 +31,36 @@ import ( ) func Test_configureVerison2p6(t *testing.T) { - url, err := common.NewURL(context.Background(), "override://0.0.0.0:0/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService") + url, err := common.NewURL("override://0.0.0.0:0/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService") assert.NoError(t, err) configurator := extension.GetConfigurator("default", &url) assert.Equal(t, "override", configurator.GetUrl().Protocol) - providerUrl, err := common.NewURL(context.Background(), "jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider×tamp=1562076628&version=&warmup=100") + providerUrl, err := common.NewURL("jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider×tamp=1562076628&version=&warmup=100") assert.NoError(t, err) configurator.Configure(&providerUrl) assert.Equal(t, "failfast", providerUrl.GetParam(constant.CLUSTER_KEY, "")) } func Test_configureVerisonOverrideAddr(t *testing.T) { - url, err := common.NewURL(context.Background(), "override://0.0.0.0:0/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService&providerAddresses=127.0.0.2:20001|127.0.0.3:20001") + url, err := common.NewURL("override://0.0.0.0:0/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService&providerAddresses=127.0.0.2:20001|127.0.0.3:20001") assert.NoError(t, err) configurator := extension.GetConfigurator("default", &url) assert.Equal(t, "override", configurator.GetUrl().Protocol) - providerUrl, err := common.NewURL(context.Background(), "jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider×tamp=1562076628&version=&warmup=100") + providerUrl, err := common.NewURL("jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider×tamp=1562076628&version=&warmup=100") assert.NoError(t, err) configurator.Configure(&providerUrl) assert.Equal(t, "failover", providerUrl.GetParam(constant.CLUSTER_KEY, "")) } func Test_configureVerison2p6WithIp(t *testing.T) { - url, err := common.NewURL(context.Background(), "override://127.0.0.1:20001/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService") + url, err := common.NewURL("override://127.0.0.1:20001/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService") assert.NoError(t, err) configurator := extension.GetConfigurator("default", &url) assert.Equal(t, "override", configurator.GetUrl().Protocol) - providerUrl, err := common.NewURL(context.Background(), "jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider×tamp=1562076628&version=&warmup=100") + providerUrl, err := common.NewURL("jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider×tamp=1562076628&version=&warmup=100") assert.NoError(t, err) configurator.Configure(&providerUrl) assert.Equal(t, "failfast", providerUrl.GetParam(constant.CLUSTER_KEY, "")) @@ -69,11 +68,11 @@ func Test_configureVerison2p6WithIp(t *testing.T) { } func Test_configureVerison2p7(t *testing.T) { - url, err := common.NewURL(context.Background(), "jsonrpc://0.0.0.0:20001/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService&configVersion=1.0&side=provider") + url, err := common.NewURL("jsonrpc://0.0.0.0:20001/com.xxx.mock.userProvider?group=1&version=1&cluster=failfast&application=BDTService&configVersion=1.0&side=provider") assert.NoError(t, err) configurator := extension.GetConfigurator("default", &url) - providerUrl, err := common.NewURL(context.Background(), "jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider×tamp=1562076628&version=&warmup=100") + providerUrl, err := common.NewURL("jsonrpc://127.0.0.1:20001/com.ikurento.user.UserProvider?anyhost=true&app.version=0.0.1&application=BDTService&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&group=&interface=com.ikurento.user.UserProvider&ip=10.32.20.124&loadbalance=random&methods.GetUser.loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=BDTService&organization=ikurento.com&owner=ZX&pid=64225&retries=0&service.filter=echo&side=provider×tamp=1562076628&version=&warmup=100") assert.NoError(t, err) configurator.Configure(&providerUrl) assert.Equal(t, "failfast", providerUrl.GetParam(constant.CLUSTER_KEY, "")) diff --git a/config_center/parser/configuration_parser.go b/config_center/parser/configuration_parser.go index 9aaa1f700f7eb581e952485681d90c051ea516f4..58fcdb49dad2c53270894a65bf4ebd9595dc420e 100644 --- a/config_center/parser/configuration_parser.go +++ b/config_center/parser/configuration_parser.go @@ -18,7 +18,6 @@ package parser import ( - "context" "strconv" "strings" ) @@ -139,14 +138,14 @@ func serviceItemToUrls(item ConfigItem, config ConfiguratorConfig) ([]*common.UR newUrlStr := urlStr newUrlStr = newUrlStr + "&application" newUrlStr = newUrlStr + v - url, err := common.NewURL(context.Background(), newUrlStr) + url, err := common.NewURL(newUrlStr) if err != nil { return nil, perrors.WithStack(err) } urls = append(urls, &url) } } else { - url, err := common.NewURL(context.Background(), urlStr) + url, err := common.NewURL(urlStr) if err != nil { return nil, perrors.WithStack(err) } @@ -185,7 +184,7 @@ func appItemToUrls(item ConfigItem, config ConfiguratorConfig) ([]*common.URL, e urlStr = urlStr + constant.APP_DYNAMIC_CONFIGURATORS_CATEGORY urlStr = urlStr + "&configVersion=" urlStr = urlStr + config.ConfigVersion - url, err := common.NewURL(context.Background(), urlStr) + url, err := common.NewURL(urlStr) if err != nil { return nil, perrors.WithStack(err) } diff --git a/config_center/zookeeper/impl.go b/config_center/zookeeper/impl.go index 6842d9e37711e954a93c7982bc959aa0798a9c93..70fb196a1eedb994eae38576de35d36deb450aaa 100644 --- a/config_center/zookeeper/impl.go +++ b/config_center/zookeeper/impl.go @@ -24,8 +24,8 @@ import ( ) import ( + "github.com/dubbogo/go-zookeeper/zk" perrors "github.com/pkg/errors" - "github.com/samuel/go-zookeeper/zk" ) import ( @@ -175,7 +175,7 @@ func (c *zookeeperDynamicConfiguration) WaitGroup() *sync.WaitGroup { return &c.wg } -func (c *zookeeperDynamicConfiguration) GetDone() chan struct{} { +func (c *zookeeperDynamicConfiguration) Done() chan struct{} { return c.done } diff --git a/config_center/zookeeper/impl_test.go b/config_center/zookeeper/impl_test.go index e614009faa5b32873c6245dea5c85cc2747e19ea..1d62f3df86f5706823cab7c9ed0bc1a7d9b380f3 100644 --- a/config_center/zookeeper/impl_test.go +++ b/config_center/zookeeper/impl_test.go @@ -17,14 +17,13 @@ package zookeeper import ( - "context" "fmt" "sync" "testing" ) import ( - "github.com/samuel/go-zookeeper/zk" + "github.com/dubbogo/go-zookeeper/zk" "github.com/stretchr/testify/assert" ) @@ -35,7 +34,7 @@ import ( ) func initZkData(group string, t *testing.T) (*zk.TestCluster, *zookeeperDynamicConfiguration) { - regurl, _ := common.NewURL(context.TODO(), "registry://127.0.0.1:1111") + regurl, _ := common.NewURL("registry://127.0.0.1:1111") ts, reg, err := newMockZookeeperDynamicConfiguration(®url) reg.SetParser(&parser.DefaultConfigurationParser{}) diff --git a/contributing.md b/contributing.md index b1265c2351789d4929d81556d72234806aed6afa..9ee2dae32fad6caaf9e19c5e98e8b99b61c26a51 100644 --- a/contributing.md +++ b/contributing.md @@ -28,4 +28,14 @@ The title format of the pull request `MUST` follow the following rules: ### 3.1 log -> 1 when logging the function's input parameter, you should add '@' before input parameter name. +>- 1 when logging the function's input parameter, you should add '@' before input parameter name. + +### 3.2 naming + +>- 1 do not use an underscore in package name, such as `filter_impl`. +>- 2 do not use an underscore in constants, such as `DUBBO_PROTOCOL`. use 'DubboProtocol' instead. + +### 3.3 comment + +>- 1 there should be comment for every export func/var. +>- 2 the comment should begin with function name/var name. \ No newline at end of file diff --git a/filter/access_key.go b/filter/access_key.go new file mode 100644 index 0000000000000000000000000000000000000000..c9bdd4ff8993d51e4d5002a1216225e2da074df5 --- /dev/null +++ b/filter/access_key.go @@ -0,0 +1,22 @@ +package filter + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/protocol" +) + +type AccessKeyPair struct { + AccessKey string `yaml:"accessKey" json:"accessKey,omitempty" property:"accessKey"` + SecretKey string `yaml:"secretKey" json:"secretKey,omitempty" property:"secretKey"` + ConsumerSide string `yaml:"consumerSide" json:"ConsumerSide,consumerSide" property:"consumerSide"` + ProviderSide string `yaml:"providerSide" json:"providerSide,omitempty" property:"providerSide"` + Creator string `yaml:"creator" json:"creator,omitempty" property:"creator"` + Options string `yaml:"options" json:"options,omitempty" property:"options"` +} + +// AccessKeyStorage +// This SPI Extension support us to store our AccessKeyPair or load AccessKeyPair from other +// storage, such as filesystem. +type AccessKeyStorage interface { + GetAccessKeyPair(protocol.Invocation, *common.URL) *AccessKeyPair +} diff --git a/filter/authenticator.go b/filter/authenticator.go new file mode 100644 index 0000000000000000000000000000000000000000..ce0547b36b03b7078784a6c05c08cd3f89611ca4 --- /dev/null +++ b/filter/authenticator.go @@ -0,0 +1,18 @@ +package filter + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/protocol" +) + +// Authenticator +type Authenticator interface { + + // Sign + // give a sign to request + Sign(protocol.Invocation, *common.URL) error + + // Authenticate + // verify the signature of the request is valid or not + Authenticate(protocol.Invocation, *common.URL) error +} diff --git a/filter/filter_impl/access_log_filter_test.go b/filter/filter_impl/access_log_filter_test.go index 14b9166b0fc486638c77388c76b49423a8d4a83e..f0de24d2a89f35876a32763eeb75495e8919ecd9 100644 --- a/filter/filter_impl/access_log_filter_test.go +++ b/filter/filter_impl/access_log_filter_test.go @@ -37,11 +37,11 @@ import ( func TestAccessLogFilter_Invoke_Not_Config(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - url, _ := common.NewURL(context.Background(), - "dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider"+ - "&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser."+ - "loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name="+ - "BDTService&organization=ikurento.com&owner=ZX®istry.role=3&retries=&"+ + url, _ := common.NewURL( + "dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider" + + "&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser." + + "loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=" + + "BDTService&organization=ikurento.com&owner=ZX®istry.role=3&retries=&" + "service.filter=echo%2Ctoken%2Caccesslog×tamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100") invoker := protocol.NewBaseInvoker(url) @@ -56,11 +56,11 @@ func TestAccessLogFilter_Invoke_Not_Config(t *testing.T) { func TestAccessLogFilter_Invoke_Default_Config(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - url, _ := common.NewURL(context.Background(), - "dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider"+ - "&cluster=failover&accesslog=true&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser."+ - "loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name="+ - "BDTService&organization=ikurento.com&owner=ZX®istry.role=3&retries=&"+ + url, _ := common.NewURL( + "dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider" + + "&cluster=failover&accesslog=true&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser." + + "loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=" + + "BDTService&organization=ikurento.com&owner=ZX®istry.role=3&retries=&" + "service.filter=echo%2Ctoken%2Caccesslog×tamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100") invoker := protocol.NewBaseInvoker(url) diff --git a/filter/filter_impl/active_filter_test.go b/filter/filter_impl/active_filter_test.go index 7b355086f9d48b3fb864ed40d1cb5db999543d77..8917e9141cad4f22ea201a9a07c2873b584c1f92 100644 --- a/filter/filter_impl/active_filter_test.go +++ b/filter/filter_impl/active_filter_test.go @@ -21,7 +21,7 @@ import ( func TestActiveFilter_Invoke(t *testing.T) { invoc := invocation.NewRPCInvocation("test", []interface{}{"OK"}, make(map[string]string, 0)) - url, _ := common.NewURL(context.TODO(), "dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider") + url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider") filter := ActiveFilter{} ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -39,7 +39,7 @@ func TestActiveFilter_OnResponse(t *testing.T) { invoc := invocation.NewRPCInvocation("test", []interface{}{"OK"}, map[string]string{ dubboInvokeStartTime: strconv.FormatInt(c-int64(elapsed), 10), }) - url, _ := common.NewURL(context.TODO(), "dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider") + url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider") filter := ActiveFilter{} ctrl := gomock.NewController(t) defer ctrl.Finish() diff --git a/filter/filter_impl/auth/accesskey_storage.go b/filter/filter_impl/auth/accesskey_storage.go new file mode 100644 index 0000000000000000000000000000000000000000..0a2bf47cbd377899ba8a0edf4a67026dd827d41f --- /dev/null +++ b/filter/filter_impl/auth/accesskey_storage.go @@ -0,0 +1,31 @@ +package auth + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/protocol" +) + +// DefaultAccesskeyStorage +// The default implementation of AccesskeyStorage +type DefaultAccesskeyStorage struct { +} + +// GetAccessKeyPair +// get AccessKeyPair from url by the key "accessKeyId" and "secretAccessKey" +func (storage *DefaultAccesskeyStorage) GetAccessKeyPair(invocation protocol.Invocation, url *common.URL) *filter.AccessKeyPair { + return &filter.AccessKeyPair{ + AccessKey: url.GetParam(constant.ACCESS_KEY_ID_KEY, ""), + SecretKey: url.GetParam(constant.SECRET_ACCESS_KEY_KEY, ""), + } +} + +func init() { + extension.SetAccesskeyStorages(constant.DEFAULT_ACCESS_KEY_STORAGE, GetDefaultAccesskeyStorage) +} + +func GetDefaultAccesskeyStorage() filter.AccessKeyStorage { + return &DefaultAccesskeyStorage{} +} diff --git a/filter/filter_impl/auth/accesskey_storage_test.go b/filter/filter_impl/auth/accesskey_storage_test.go new file mode 100644 index 0000000000000000000000000000000000000000..6ab861a8673b191be0a8063980e1dc53e4e70f60 --- /dev/null +++ b/filter/filter_impl/auth/accesskey_storage_test.go @@ -0,0 +1,28 @@ +package auth + +import ( + "net/url" + "testing" +) + +import ( + "github.com/stretchr/testify/assert" +) + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + invocation2 "github.com/apache/dubbo-go/protocol/invocation" +) + +func TestDefaultAccesskeyStorage_GetAccesskeyPair(t *testing.T) { + url := common.NewURLWithOptions( + common.WithParams(url.Values{}), + common.WithParamsValue(constant.SECRET_ACCESS_KEY_KEY, "skey"), + common.WithParamsValue(constant.ACCESS_KEY_ID_KEY, "akey")) + invocation := &invocation2.RPCInvocation{} + storage := GetDefaultAccesskeyStorage() + accesskeyPair := storage.GetAccessKeyPair(invocation, url) + assert.Equal(t, "skey", accesskeyPair.SecretKey) + assert.Equal(t, "akey", accesskeyPair.AccessKey) +} diff --git a/filter/filter_impl/auth/consumer_sign.go b/filter/filter_impl/auth/consumer_sign.go new file mode 100644 index 0000000000000000000000000000000000000000..be86b5c74bb9fd02b96483edb18571d47d205ee7 --- /dev/null +++ b/filter/filter_impl/auth/consumer_sign.go @@ -0,0 +1,43 @@ +package auth + +import ( + "context" + "fmt" +) +import ( + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/common/logger" + "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/protocol" +) + +// ConsumerSignFilter +// This filter is working for signing the request on consumer side +type ConsumerSignFilter struct { +} + +func init() { + extension.SetFilter(constant.CONSUMER_SIGN_FILTER, getConsumerSignFilter) +} + +func (csf *ConsumerSignFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { + logger.Infof("invoking ConsumerSign filter.") + url := invoker.GetUrl() + + err := doAuthWork(&url, func(authenticator filter.Authenticator) error { + return authenticator.Sign(invocation, &url) + }) + if err != nil { + panic(fmt.Sprintf("Sign for invocation %s # %s failed", url.ServiceKey(), invocation.MethodName())) + + } + return invoker.Invoke(ctx, invocation) +} + +func (csf *ConsumerSignFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { + return result +} +func getConsumerSignFilter() filter.Filter { + return &ConsumerSignFilter{} +} diff --git a/filter/filter_impl/auth/consumer_sign_test.go b/filter/filter_impl/auth/consumer_sign_test.go new file mode 100644 index 0000000000000000000000000000000000000000..9a90970b898b75f3c3f1b195062538e62505a082 --- /dev/null +++ b/filter/filter_impl/auth/consumer_sign_test.go @@ -0,0 +1,37 @@ +package auth + +import ( + "context" + "testing" +) + +import ( + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" +) + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/protocol" + "github.com/apache/dubbo-go/protocol/invocation" + "github.com/apache/dubbo-go/protocol/mock" +) + +func TestConsumerSignFilter_Invoke(t *testing.T) { + url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0") + url.SetParam(constant.SECRET_ACCESS_KEY_KEY, "sk") + url.SetParam(constant.ACCESS_KEY_ID_KEY, "ak") + inv := invocation.NewRPCInvocation("test", []interface{}{"OK"}, nil) + filter := &ConsumerSignFilter{} + ctrl := gomock.NewController(t) + defer ctrl.Finish() + invoker := mock.NewMockInvoker(ctrl) + result := &protocol.RPCResult{} + invoker.EXPECT().Invoke(inv).Return(result).Times(2) + invoker.EXPECT().GetUrl().Return(url).Times(2) + assert.Equal(t, result, filter.Invoke(context.Background(), invoker, inv)) + + url.SetParam(constant.SERVICE_AUTH_KEY, "true") + assert.Equal(t, result, filter.Invoke(context.Background(), invoker, inv)) +} diff --git a/filter/filter_impl/auth/default_authenticator.go b/filter/filter_impl/auth/default_authenticator.go new file mode 100644 index 0000000000000000000000000000000000000000..73eb9cddc0e1b7b4747da4b0f3e883075e349226 --- /dev/null +++ b/filter/filter_impl/auth/default_authenticator.go @@ -0,0 +1,120 @@ +package auth + +import ( + "errors" + "fmt" + "github.com/apache/dubbo-go/filter" + "strconv" + "time" +) + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/protocol" + invocation_impl "github.com/apache/dubbo-go/protocol/invocation" +) + +func init() { + extension.SetAuthenticator(constant.DEFAULT_AUTHENTICATOR, GetDefaultAuthenticator) +} + +// DefaultAuthenticator +// The default implemetation of Authenticator +type DefaultAuthenticator struct { +} + +// Sign +// add the signature for the invocation +func (authenticator *DefaultAuthenticator) Sign(invocation protocol.Invocation, url *common.URL) error { + currentTimeMillis := strconv.Itoa(int(time.Now().Unix() * 1000)) + + consumer := url.GetParam(constant.APPLICATION_KEY, "") + accessKeyPair, err := getAccessKeyPair(invocation, url) + if err != nil { + return errors.New("get accesskey pair failed, cause: " + err.Error()) + } + inv := invocation.(*invocation_impl.RPCInvocation) + signature, err := getSignature(url, invocation, accessKeyPair.SecretKey, currentTimeMillis) + if err != nil { + return err + } + inv.SetAttachments(constant.REQUEST_SIGNATURE_KEY, signature) + inv.SetAttachments(constant.REQUEST_TIMESTAMP_KEY, currentTimeMillis) + inv.SetAttachments(constant.AK_KEY, accessKeyPair.AccessKey) + inv.SetAttachments(constant.CONSUMER, consumer) + return nil +} + +// getSignature +// get signature by the metadata and params of the invocation +func getSignature(url *common.URL, invocation protocol.Invocation, secrectKey string, currentTime string) (string, error) { + + requestString := fmt.Sprintf(constant.SIGNATURE_STRING_FORMAT, + url.ColonSeparatedKey(), invocation.MethodName(), secrectKey, currentTime) + var signature string + if parameterEncrypt := url.GetParamBool(constant.PARAMTER_SIGNATURE_ENABLE_KEY, false); parameterEncrypt { + var err error + if signature, err = SignWithParams(invocation.Arguments(), requestString, secrectKey); err != nil { + // TODO + return "", errors.New("sign the request with params failed, cause:" + err.Error()) + } + } else { + signature = Sign(requestString, secrectKey) + } + + return signature, nil +} + +// Authenticate +// This method verifies whether the signature sent by the requester is correct +func (authenticator *DefaultAuthenticator) Authenticate(invocation protocol.Invocation, url *common.URL) error { + accessKeyId := invocation.AttachmentsByKey(constant.AK_KEY, "") + + requestTimestamp := invocation.AttachmentsByKey(constant.REQUEST_TIMESTAMP_KEY, "") + originSignature := invocation.AttachmentsByKey(constant.REQUEST_SIGNATURE_KEY, "") + consumer := invocation.AttachmentsByKey(constant.CONSUMER, "") + if IsEmpty(accessKeyId, false) || IsEmpty(consumer, false) || + IsEmpty(requestTimestamp, false) || IsEmpty(originSignature, false) { + return errors.New("failed to authenticate your ak/sk, maybe the consumer has not enabled the auth") + } + + accessKeyPair, err := getAccessKeyPair(invocation, url) + if err != nil { + return errors.New("failed to authenticate , can't load the accessKeyPair") + } + + computeSignature, err := getSignature(url, invocation, accessKeyPair.SecretKey, requestTimestamp) + if err != nil { + return err + } + if success := computeSignature == originSignature; !success { + return errors.New("failed to authenticate, signature is not correct") + } + return nil +} + +func getAccessKeyPair(invocation protocol.Invocation, url *common.URL) (*filter.AccessKeyPair, error) { + accesskeyStorage := extension.GetAccesskeyStorages(url.GetParam(constant.ACCESS_KEY_STORAGE_KEY, constant.DEFAULT_ACCESS_KEY_STORAGE)) + accessKeyPair := accesskeyStorage.GetAccessKeyPair(invocation, url) + if accessKeyPair == nil || IsEmpty(accessKeyPair.AccessKey, false) || IsEmpty(accessKeyPair.SecretKey, true) { + return nil, errors.New("accessKeyId or secretAccessKey not found") + } else { + return accessKeyPair, nil + } +} + +func GetDefaultAuthenticator() filter.Authenticator { + return &DefaultAuthenticator{} +} + +func doAuthWork(url *common.URL, do func(filter.Authenticator) error) error { + + shouldAuth := url.GetParamBool(constant.SERVICE_AUTH_KEY, false) + if shouldAuth { + authenticator := extension.GetAuthenticator(url.GetParam(constant.AUTHENTICATOR_KEY, constant.DEFAULT_AUTHENTICATOR)) + return do(authenticator) + } + return nil +} diff --git a/filter/filter_impl/auth/default_authenticator_test.go b/filter/filter_impl/auth/default_authenticator_test.go new file mode 100644 index 0000000000000000000000000000000000000000..72220eec99533b73cc2c9159e3443d6f566471fa --- /dev/null +++ b/filter/filter_impl/auth/default_authenticator_test.go @@ -0,0 +1,130 @@ +package auth + +import ( + "fmt" + "net/url" + "strconv" + "testing" + "time" +) + +import ( + "github.com/stretchr/testify/assert" +) + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/protocol/invocation" +) + +func TestDefaultAuthenticator_Authenticate(t *testing.T) { + secret := "dubbo-sk" + access := "dubbo-ak" + testurl, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0") + testurl.SetParam(constant.PARAMTER_SIGNATURE_ENABLE_KEY, "true") + testurl.SetParam(constant.ACCESS_KEY_ID_KEY, access) + testurl.SetParam(constant.SECRET_ACCESS_KEY_KEY, secret) + parmas := []interface{}{"OK", struct { + Name string + Id int64 + }{"YUYU", 1}} + inv := invocation.NewRPCInvocation("test", parmas, nil) + requestTime := strconv.Itoa(int(time.Now().Unix() * 1000)) + signature, _ := getSignature(&testurl, inv, secret, requestTime) + + var authenticator = &DefaultAuthenticator{} + + invcation := invocation.NewRPCInvocation("test", parmas, map[string]string{ + constant.REQUEST_SIGNATURE_KEY: signature, + constant.CONSUMER: "test", + constant.REQUEST_TIMESTAMP_KEY: requestTime, + constant.AK_KEY: access, + }) + err := authenticator.Authenticate(invcation, &testurl) + assert.Nil(t, err) + // modify the params + invcation = invocation.NewRPCInvocation("test", parmas[:1], map[string]string{ + constant.REQUEST_SIGNATURE_KEY: signature, + constant.CONSUMER: "test", + constant.REQUEST_TIMESTAMP_KEY: requestTime, + constant.AK_KEY: access, + }) + err = authenticator.Authenticate(invcation, &testurl) + assert.NotNil(t, err) + +} + +func TestDefaultAuthenticator_Sign(t *testing.T) { + authenticator := &DefaultAuthenticator{} + testurl, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?application=test&interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0") + testurl.SetParam(constant.ACCESS_KEY_ID_KEY, "akey") + testurl.SetParam(constant.SECRET_ACCESS_KEY_KEY, "skey") + testurl.SetParam(constant.PARAMTER_SIGNATURE_ENABLE_KEY, "false") + inv := invocation.NewRPCInvocation("test", []interface{}{"OK"}, nil) + _ = authenticator.Sign(inv, &testurl) + assert.NotEqual(t, inv.AttachmentsByKey(constant.REQUEST_SIGNATURE_KEY, ""), "") + assert.NotEqual(t, inv.AttachmentsByKey(constant.CONSUMER, ""), "") + assert.NotEqual(t, inv.AttachmentsByKey(constant.REQUEST_TIMESTAMP_KEY, ""), "") + assert.Equal(t, inv.AttachmentsByKey(constant.AK_KEY, ""), "akey") + +} + +func Test_getAccessKeyPairSuccess(t *testing.T) { + testurl := common.NewURLWithOptions( + common.WithParams(url.Values{}), + common.WithParamsValue(constant.SECRET_ACCESS_KEY_KEY, "skey"), + common.WithParamsValue(constant.ACCESS_KEY_ID_KEY, "akey")) + invcation := invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, nil) + _, e := getAccessKeyPair(invcation, testurl) + assert.Nil(t, e) +} + +func Test_getAccessKeyPairFailed(t *testing.T) { + defer func() { + e := recover() + assert.NotNil(t, e) + }() + testurl := common.NewURLWithOptions( + common.WithParams(url.Values{}), + common.WithParamsValue(constant.ACCESS_KEY_ID_KEY, "akey")) + invcation := invocation.NewRPCInvocation("MethodName", []interface{}{"OK"}, nil) + _, e := getAccessKeyPair(invcation, testurl) + assert.NotNil(t, e) + testurl = common.NewURLWithOptions( + common.WithParams(url.Values{}), + common.WithParamsValue(constant.SECRET_ACCESS_KEY_KEY, "skey"), + common.WithParamsValue(constant.ACCESS_KEY_ID_KEY, "akey"), common.WithParamsValue(constant.ACCESS_KEY_STORAGE_KEY, "dubbo")) + _, e = getAccessKeyPair(invcation, testurl) + +} + +func Test_getSignatureWithinParams(t *testing.T) { + testurl, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0") + testurl.SetParam(constant.PARAMTER_SIGNATURE_ENABLE_KEY, "true") + inv := invocation.NewRPCInvocation("test", []interface{}{"OK"}, map[string]string{ + "": "", + }) + secret := "dubbo" + current := strconv.Itoa(int(time.Now().Unix() * 1000)) + signature, _ := getSignature(&testurl, inv, secret, current) + requestString := fmt.Sprintf(constant.SIGNATURE_STRING_FORMAT, + testurl.ColonSeparatedKey(), inv.MethodName(), secret, current) + s, _ := SignWithParams(inv.Arguments(), requestString, secret) + assert.False(t, IsEmpty(signature, false)) + assert.Equal(t, s, signature) +} + +func Test_getSignature(t *testing.T) { + testurl, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0") + testurl.SetParam(constant.PARAMTER_SIGNATURE_ENABLE_KEY, "false") + inv := invocation.NewRPCInvocation("test", []interface{}{"OK"}, nil) + secret := "dubbo" + current := strconv.Itoa(int(time.Now().Unix() * 1000)) + signature, _ := getSignature(&testurl, inv, secret, current) + requestString := fmt.Sprintf(constant.SIGNATURE_STRING_FORMAT, + testurl.ColonSeparatedKey(), inv.MethodName(), secret, current) + s := Sign(requestString, secret) + assert.False(t, IsEmpty(signature, false)) + assert.Equal(t, s, signature) +} diff --git a/filter/filter_impl/auth/provider_auth.go b/filter/filter_impl/auth/provider_auth.go new file mode 100644 index 0000000000000000000000000000000000000000..90804934f6b01a61f021f61f4ee549d744ccee72 --- /dev/null +++ b/filter/filter_impl/auth/provider_auth.go @@ -0,0 +1,43 @@ +package auth + +import ( + "context" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/common/logger" + "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/protocol" +) + +// ProviderAuthFilter +// This filter is used to verify the correctness of the signature on provider side +type ProviderAuthFilter struct { +} + +func init() { + extension.SetFilter(constant.PROVIDER_AUTH_FILTER, getProviderAuthFilter) +} + +func (paf *ProviderAuthFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { + logger.Infof("invoking providerAuth filter.") + url := invoker.GetUrl() + + err := doAuthWork(&url, func(authenticator filter.Authenticator) error { + return authenticator.Authenticate(invocation, &url) + }) + if err != nil { + logger.Infof("auth the request: %v occur exception, cause: %s", invocation, err.Error()) + return &protocol.RPCResult{ + Err: err, + } + } + + return invoker.Invoke(ctx, invocation) +} + +func (paf *ProviderAuthFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { + return result +} +func getProviderAuthFilter() filter.Filter { + return &ProviderAuthFilter{} +} diff --git a/filter/filter_impl/auth/provider_auth_test.go b/filter/filter_impl/auth/provider_auth_test.go new file mode 100644 index 0000000000000000000000000000000000000000..88d6423458d5534f18da4316ffe1bca0b374e43c --- /dev/null +++ b/filter/filter_impl/auth/provider_auth_test.go @@ -0,0 +1,57 @@ +package auth + +import ( + "context" + "strconv" + "testing" + "time" +) + +import ( + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" +) + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/protocol" + "github.com/apache/dubbo-go/protocol/invocation" + "github.com/apache/dubbo-go/protocol/mock" +) + +func TestProviderAuthFilter_Invoke(t *testing.T) { + secret := "dubbo-sk" + access := "dubbo-ak" + url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=gg&version=2.6.0") + url.SetParam(constant.ACCESS_KEY_ID_KEY, access) + url.SetParam(constant.SECRET_ACCESS_KEY_KEY, secret) + parmas := []interface{}{ + "OK", + struct { + Name string + Id int64 + }{"YUYU", 1}, + } + inv := invocation.NewRPCInvocation("test", parmas, nil) + requestTime := strconv.Itoa(int(time.Now().Unix() * 1000)) + signature, _ := getSignature(&url, inv, secret, requestTime) + + inv = invocation.NewRPCInvocation("test", []interface{}{"OK"}, map[string]string{ + constant.REQUEST_SIGNATURE_KEY: signature, + constant.CONSUMER: "test", + constant.REQUEST_TIMESTAMP_KEY: requestTime, + constant.AK_KEY: access, + }) + ctrl := gomock.NewController(t) + filter := &ProviderAuthFilter{} + defer ctrl.Finish() + invoker := mock.NewMockInvoker(ctrl) + result := &protocol.RPCResult{} + invoker.EXPECT().Invoke(inv).Return(result).Times(2) + invoker.EXPECT().GetUrl().Return(url).Times(2) + assert.Equal(t, result, filter.Invoke(context.Background(), invoker, inv)) + url.SetParam(constant.SERVICE_AUTH_KEY, "true") + assert.Equal(t, result, filter.Invoke(context.Background(), invoker, inv)) + +} diff --git a/filter/filter_impl/auth/sign_util.go b/filter/filter_impl/auth/sign_util.go new file mode 100644 index 0000000000000000000000000000000000000000..60698439c5abc1ff0cc555b2ceec77bf2e0e53d5 --- /dev/null +++ b/filter/filter_impl/auth/sign_util.go @@ -0,0 +1,55 @@ +package auth + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "encoding/json" + "errors" + "strings" +) + +// Sign +// get a signature string with given information, such as metadata or parameters +func Sign(metadata, key string) string { + return doSign([]byte(metadata), key) +} + +func SignWithParams(params []interface{}, metadata, key string) (string, error) { + if params == nil || len(params) == 0 { + return Sign(metadata, key), nil + } + + data := append(params, metadata) + if bytes, err := toBytes(data); err != nil { + // TODO + return "", errors.New("data convert to bytes failed") + } else { + return doSign(bytes, key), nil + } +} + +func toBytes(data []interface{}) ([]byte, error) { + if bytes, err := json.Marshal(data); err != nil { + return nil, errors.New("") + } else { + return bytes, nil + } +} + +func doSign(bytes []byte, key string) string { + mac := hmac.New(sha256.New, []byte(key)) + mac.Write(bytes) + signature := mac.Sum(nil) + return base64.URLEncoding.EncodeToString(signature) +} + +func IsEmpty(s string, allowSpace bool) bool { + if len(s) == 0 { + return true + } + if !allowSpace { + return strings.TrimSpace(s) == "" + } + return false +} diff --git a/filter/filter_impl/auth/sign_util_test.go b/filter/filter_impl/auth/sign_util_test.go new file mode 100644 index 0000000000000000000000000000000000000000..de6154e8854af99f8e862d94ee45aefcbf26b12b --- /dev/null +++ b/filter/filter_impl/auth/sign_util_test.go @@ -0,0 +1,84 @@ +package auth + +import ( + "testing" +) + +import ( + "github.com/stretchr/testify/assert" +) + +func TestIsEmpty(t *testing.T) { + type args struct { + s string + allowSpace bool + } + tests := []struct { + name string + args args + want bool + }{ + // TODO: Add test cases. + {"test1", args{s: " ", allowSpace: false}, true}, + {"test2", args{s: " ", allowSpace: true}, false}, + {"test3", args{s: "hello,dubbo", allowSpace: false}, false}, + {"test4", args{s: "hello,dubbo", allowSpace: true}, false}, + {"test5", args{s: "", allowSpace: true}, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := IsEmpty(tt.args.s, tt.args.allowSpace); got != tt.want { + t.Errorf("IsEmpty() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestSign(t *testing.T) { + metadata := "com.ikurento.user.UserProvider::sayHi" + key := "key" + signature := Sign(metadata, key) + assert.NotNil(t, signature) + +} + +func TestSignWithParams(t *testing.T) { + metadata := "com.ikurento.user.UserProvider::sayHi" + key := "key" + params := []interface{}{ + "a", 1, struct { + Name string + Id int64 + }{"YuYu", 1}, + } + signature, _ := SignWithParams(params, metadata, key) + assert.False(t, IsEmpty(signature, false)) +} + +func Test_doSign(t *testing.T) { + sign := doSign([]byte("DubboGo"), "key") + sign1 := doSign([]byte("DubboGo"), "key") + sign2 := doSign([]byte("DubboGo"), "key2") + assert.NotNil(t, sign) + assert.Equal(t, sign1, sign) + assert.NotEqual(t, sign1, sign2) +} + +func Test_toBytes(t *testing.T) { + params := []interface{}{ + "a", 1, struct { + Name string + Id int64 + }{"YuYu", 1}, + } + params2 := []interface{}{ + "a", 1, struct { + Name string + Id int64 + }{"YuYu", 1}, + } + jsonBytes, _ := toBytes(params) + jsonBytes2, _ := toBytes(params2) + assert.NotNil(t, jsonBytes) + assert.Equal(t, jsonBytes, jsonBytes2) +} diff --git a/filter/filter_impl/generic_service_filter_test.go b/filter/filter_impl/generic_service_filter_test.go index 24ed3b95fcab6111f5c432a12c41dd0b60b4a5a2..37c6af7450a75449fce51182684be2f619eda9d8 100644 --- a/filter/filter_impl/generic_service_filter_test.go +++ b/filter/filter_impl/generic_service_filter_test.go @@ -99,7 +99,7 @@ func TestGenericServiceFilter_Invoke(t *testing.T) { _, _ = common.ServiceMap.Register("testprotocol", s) rpcInvocation := invocation.NewRPCInvocation(methodName, aurguments, nil) filter := GetGenericServiceFilter() - url, _ := common.NewURL(context.Background(), "testprotocol://127.0.0.1:20000/com.test.Path") + url, _ := common.NewURL("testprotocol://127.0.0.1:20000/com.test.Path") result := filter.Invoke(context.Background(), &proxy_factory.ProxyInvoker{BaseInvoker: *protocol.NewBaseInvoker(url)}, rpcInvocation) assert.NotNil(t, result) assert.Nil(t, result.Error()) diff --git a/filter/filter_impl/metrics_filter.go b/filter/filter_impl/metrics_filter.go new file mode 100644 index 0000000000000000000000000000000000000000..f4734172b74c8bbcdac5c9a9743acb4df5fcb6b5 --- /dev/null +++ b/filter/filter_impl/metrics_filter.go @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package filter_impl + +import ( + "context" + "time" +) + +import ( + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/config" + "github.com/apache/dubbo-go/filter" + "github.com/apache/dubbo-go/metrics" + "github.com/apache/dubbo-go/protocol" +) + +const ( + metricFilterName = "metrics" +) + +var ( + metricFilterInstance filter.Filter +) + +// must initialized before using the filter and after loading configuration +func init() { + extension.SetFilter(metricFilterName, newMetricsFilter) +} + +// metricFilter will calculate the invocation's duration and the report to the reporters +// If you want to use this filter to collect the metrics, +// Adding this into your configuration file, like: +// filter: "metrics" +// metrics: +// reporter: +// - "your reporter" # here you should specify the reporter, for example 'prometheus' +// more info please take a look at dubbo-samples projects +type metricsFilter struct { + reporters []metrics.Reporter +} + +// Invoke collect the duration of invocation and then report the duration by using goroutine +func (p *metricsFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { + start := time.Now() + res := invoker.Invoke(ctx, invocation) + end := time.Now() + duration := end.Sub(start) + go func() { + for _, reporter := range p.reporters { + reporter.Report(ctx, invoker, invocation, duration, res) + } + }() + return res +} + +// OnResponse do nothing and return the result +func (p *metricsFilter) OnResponse(ctx context.Context, res protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { + return res +} + +// newMetricsFilter the metricsFilter is singleton. +// it's lazy initialization +// make sure that the configuration had been loaded before invoking this method. +func newMetricsFilter() filter.Filter { + if metricFilterInstance == nil { + reporterNames := config.GetMetricConfig().Reporters + reporters := make([]metrics.Reporter, 0, len(reporterNames)) + for _, name := range reporterNames { + reporters = append(reporters, extension.GetMetricReporter(name)) + } + metricFilterInstance = &metricsFilter{ + reporters: reporters, + } + } + + return metricFilterInstance +} diff --git a/filter/filter_impl/metrics_filter_test.go b/filter/filter_impl/metrics_filter_test.go new file mode 100644 index 0000000000000000000000000000000000000000..709404a2af4f4df0dbf625dbbbd673e34975c0db --- /dev/null +++ b/filter/filter_impl/metrics_filter_test.go @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package filter_impl + +import ( + "context" + "sync" + "testing" + "time" +) + +import ( + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/config" + "github.com/apache/dubbo-go/metrics" + "github.com/apache/dubbo-go/protocol" + "github.com/apache/dubbo-go/protocol/invocation" +) + +func TestMetricsFilter_Invoke(t *testing.T) { + + // prepare the mock reporter + config.GetMetricConfig().Reporters = []string{"mock"} + mk := &mockReporter{} + extension.SetMetricReporter("mock", func() metrics.Reporter { + return mk + }) + + instance := extension.GetFilter(metricFilterName) + + url, _ := common.NewURL( + "dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider" + + "&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser." + + "loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=" + + "BDTService&organization=ikurento.com&owner=ZX®istry.role=3&retries=&" + + "service.filter=echo%2Ctoken%2Caccesslog×tamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100") + invoker := protocol.NewBaseInvoker(url) + + attach := make(map[string]string, 10) + inv := invocation.NewRPCInvocation("MethodName", []interface{}{"OK", "Hello"}, attach) + + ctx := context.Background() + + mk.On("Report", ctx, invoker, inv).Return(true, nil) + + mk.wg.Add(1) + result := instance.Invoke(ctx, invoker, inv) + assert.NotNil(t, result) + mk.AssertNotCalled(t, "Report", 1) + // it will do nothing + result = instance.OnResponse(ctx, nil, invoker, inv) + assert.Nil(t, result) +} + +type mockReporter struct { + mock.Mock + wg sync.WaitGroup +} + +func (m *mockReporter) Report(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation, cost time.Duration, res protocol.Result) { + m.Called(ctx, invoker, invocation) + m.wg.Done() +} diff --git a/filter/filter_impl/tracing_filter_test.go b/filter/filter_impl/tracing_filter_test.go index c6d6673f3a45e7d73ffd71373b5a7a2860d36a52..a51692dddcc3400032650f4953eb1e28fb047709 100644 --- a/filter/filter_impl/tracing_filter_test.go +++ b/filter/filter_impl/tracing_filter_test.go @@ -37,11 +37,11 @@ import ( ) func TestTracingFilter_Invoke(t *testing.T) { - url, _ := common.NewURL(context.Background(), - "dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider"+ - "&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser."+ - "loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name="+ - "BDTService&organization=ikurento.com&owner=ZX®istry.role=3&retries=&"+ + url, _ := common.NewURL( + "dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider" + + "&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser." + + "loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=" + + "BDTService&organization=ikurento.com&owner=ZX®istry.role=3&retries=&" + "service.filter=echo%2Ctoken%2Caccesslog×tamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100") invoker := protocol.NewBaseInvoker(url) diff --git a/go.mod b/go.mod index db6dc92c63176334f6dfa0436889ffab6f3c9c53..54b39d322e83e05c4c54ffdf166dd4f0aa039249 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect github.com/creasty/defaults v1.3.0 github.com/dubbogo/getty v1.3.2 + github.com/dubbogo/go-zookeeper v1.0.0 github.com/dubbogo/gost v1.5.2 github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect github.com/go-errors/errors v1.0.1 // indirect @@ -37,8 +38,7 @@ require ( github.com/nacos-group/nacos-sdk-go v0.0.0-20190723125407-0242d42e3dbb github.com/opentracing/opentracing-go v1.1.0 github.com/pkg/errors v0.8.1 - github.com/prometheus/client_golang v1.1.0 // indirect - github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec + github.com/prometheus/client_golang v1.1.0 github.com/satori/go.uuid v1.2.0 github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 // indirect github.com/soheilhy/cmux v0.1.4 // indirect diff --git a/go.sum b/go.sum index f215a81b209579c0bb5de0123153b10b7a36767b..0461f29653568944637306d65a6addbd79df664f 100644 --- a/go.sum +++ b/go.sum @@ -22,8 +22,6 @@ github.com/SAP/go-hdb v0.12.0 h1:5hBQZ2jjyZ268qjDmoDZJuCyLzR6oRLI60eYzmTW9m4= github.com/SAP/go-hdb v0.12.0/go.mod h1:etBT+FAi1t5k3K3tf5vQTnosgYmhDkRi8jEnQqCnxF0= github.com/SermoDigital/jose v0.0.0-20180104203859-803625baeddc h1:LkkwnbY+S8WmwkWq1SVyRWMH9nYWO1P5XN3OD1tts/w= github.com/SermoDigital/jose v0.0.0-20180104203859-803625baeddc/go.mod h1:ARgCUhI1MHQH+ONky/PAtmVHQrP5JlGY0F3poXOp/fA= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/Workiva/go-datastructures v1.0.50 h1:slDmfW6KCHcC7U+LP3DDBbm4fqTwZGn1beOFPfGaLvo= @@ -106,18 +104,16 @@ github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dubbogo/getty v1.3.2 h1:l1KVSs/1CtTKbIPTrkTtBT6S9ddvmswDGoAnnl2CDpM= github.com/dubbogo/getty v1.3.2/go.mod h1:ANbVQ9tbpZ2b0xdR8nRrgS/oXIsZAeRxzvPSOn/7mbk= +github.com/dubbogo/go-zookeeper v1.0.0 h1:RsYdlGwhDW+iKXM3eIIcvt34P2swLdmQfuIJxsHlGoM= +github.com/dubbogo/go-zookeeper v1.0.0/go.mod h1:fn6n2CAEer3novYgk9ULLwAjuV8/g4DdC2ENwRb6E+c= github.com/dubbogo/gost v1.5.1 h1:oG5dzaWf1KYynBaBoUIOkgT+YD0niHV6xxI0Odq7hDg= github.com/dubbogo/gost v1.5.1/go.mod h1:pPTjVyoJan3aPxBPNUX0ADkXjPibLo+/Ib0/fADXSG8= github.com/dubbogo/gost v1.5.2 h1:ri/03971hdpnn3QeCU+4UZgnRNGDXLDGDucR/iozZm8= github.com/dubbogo/gost v1.5.2/go.mod h1:pPTjVyoJan3aPxBPNUX0ADkXjPibLo+/Ib0/fADXSG8= github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74 h1:2MIhn2R6oXQbgW5yHfS+d6YqyMfXiu2L55rFZC4UD/M= github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74/go.mod h1:UqXY1lYT/ERa4OEAywUqdok1T4RCRdArkhic1Opuavo= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/elazarl/go-bindata-assetfs v0.0.0-20160803192304-e1a2a7ec64b0 h1:ZoRgc53qJCfSLimXqJDrmBhnt5GChDsExMCK7t48o0Y= github.com/elazarl/go-bindata-assetfs v0.0.0-20160803192304-e1a2a7ec64b0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= -github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.8.0 h1:uE6Fp4fOcAJdc1wTQXLJ+SYistkbG1dNoi6Zs1+Ybvk= github.com/envoyproxy/go-control-plane v0.8.0/go.mod h1:GSSbY9P1neVhdY7G4wu+IK1rk/dqhiCC/4ExuWJZVuk= github.com/envoyproxy/protoc-gen-validate v0.0.14 h1:YBW6/cKy9prEGRYLnaGa4IDhzxZhRCtKsax8srGKDnM= @@ -152,7 +148,6 @@ github.com/gocql/gocql v0.0.0-20180617115710-e06f8c1bcd78/go.mod h1:4Fw1eo5iaEhD github.com/gogo/googleapis v1.1.0 h1:kFkMAZBNAn4j7K0GiZr8cRYzejq68VbheufiV3YuyFI= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= @@ -191,9 +186,6 @@ github.com/gophercloud/gophercloud v0.0.0-20180828235145-f29afc2cceca/go.mod h1: github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= @@ -329,7 +321,6 @@ github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 h1:Bvq8AziQ5j github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042/go.mod h1:TPpsiPUEh0zFL1Snz4crhMlBe60PYxRHr5oFF3rRYg0= github.com/lib/pq v0.0.0-20180523175426-90697d60dd84 h1:it29sI2IM490luSc3RAhp5WuCYnc6RtbfLVAB7nmC5M= github.com/lib/pq v0.0.0-20180523175426-90697d60dd84/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= @@ -372,22 +363,16 @@ github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2/go.mod h github.com/oklog/run v0.0.0-20180308005104-6934b124db28 h1:Hbr3fbVPXea52oPQeP7KLSxP52g6SFaNY1IqAmUyEW0= github.com/oklog/run v0.0.0-20180308005104-6934b124db28/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= -github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/ory/dockertest v3.3.4+incompatible h1:VrpM6Gqg7CrPm3bL4Wm1skO+zFWLbh7/Xb5kGEbJRh8= github.com/ory/dockertest v3.3.4+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c h1:vwpFWvAO8DeIZfFeqASzZfsxuWPno9ncAebBEP0N3uE= @@ -399,11 +384,9 @@ github.com/patrickmn/go-cache v0.0.0-20180527043350-9f6ff22cfff8 h1:BR6MM54q4W9p github.com/patrickmn/go-cache v0.0.0-20180527043350-9f6ff22cfff8/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w= @@ -425,15 +408,12 @@ github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 h1:Wdi9nwnhFNAlseAOekn6B5G/+GMtks9UKbvRU/CMM/o= github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03/go.mod h1:gRAiPF5C5Nd0eyyRdqIu9qTiFSoZzpTq727b5B8fkkU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735 h1:7YvPJVmEeFHR1Tj9sZEYsmarJEQfMVYpd/Vyy/A8dqE= github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec h1:6ncX5ko6B9LntYM0YBRXkiSaZMmLYeZ/NWcmeB43mMY= -github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= @@ -460,7 +440,6 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -480,7 +459,6 @@ github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3 h1:kF/7m/ZU+0D github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3/go.mod h1:QDlpd3qS71vYtakd2hmdpqhJ9nwv6mD6A30bQ1BPBFE= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/uber/jaeger-client-go v2.17.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/vmware/govmomi v0.18.0 h1:f7QxSmP7meCtoAmiKZogvVbLInT+CZx6Px6K5rYsJZo= github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= @@ -559,7 +537,6 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.22.1 h1:/7cs52RnTJmD43s3uxzlq2U7nqVTd/37viQwMrMNlOM= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= diff --git a/metrics/prometheus/reporter.go b/metrics/prometheus/reporter.go new file mode 100644 index 0000000000000000000000000000000000000000..1636b14da2fe5ab714853aa662eaa774ddbc1791 --- /dev/null +++ b/metrics/prometheus/reporter.go @@ -0,0 +1,184 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package prometheus + +import ( + "context" + "strconv" + "strings" + "sync" + "time" +) +import ( + "github.com/prometheus/client_golang/prometheus" +) + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/common/logger" + "github.com/apache/dubbo-go/config" + "github.com/apache/dubbo-go/metrics" + "github.com/apache/dubbo-go/protocol" +) + +const ( + reporterName = "prometheus" + serviceKey = constant.SERVICE_KEY + groupKey = constant.GROUP_KEY + versionKey = constant.VERSION_KEY + methodKey = constant.METHOD_KEY + timeoutKey = constant.TIMEOUT_KEY + + providerKey = "provider" + consumerKey = "consumer" + + // to identify the metric's type + histogramSuffix = "_histogram" + // to identify the metric's type + summarySuffix = "_summary" +) + +var ( + labelNames = []string{serviceKey, groupKey, versionKey, methodKey, timeoutKey} + namespace = config.GetApplicationConfig().Name + reporterInstance *PrometheusReporter + reporterInitOnce sync.Once +) + +// should initialize after loading configuration +func init() { + + extension.SetMetricReporter(reporterName, newPrometheusReporter) +} + +// PrometheusReporter +// it will collect the data for Prometheus +// if you want to use this, you should initialize your prometheus. +// https://prometheus.io/docs/guides/go-application/ +type PrometheusReporter struct { + + // report the consumer-side's summary data + consumerSummaryVec *prometheus.SummaryVec + // report the provider-side's summary data + providerSummaryVec *prometheus.SummaryVec + + // report the provider-side's histogram data + providerHistogramVec *prometheus.HistogramVec + // report the consumer-side's histogram data + consumerHistogramVec *prometheus.HistogramVec +} + +// Report report the duration to Prometheus +// the role in url must be consumer or provider +// or it will be ignored +func (reporter *PrometheusReporter) Report(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation, cost time.Duration, res protocol.Result) { + url := invoker.GetUrl() + var sumVec *prometheus.SummaryVec + var hisVec *prometheus.HistogramVec + if isProvider(url) { + sumVec = reporter.providerSummaryVec + hisVec = reporter.providerHistogramVec + } else if isConsumer(url) { + sumVec = reporter.consumerSummaryVec + hisVec = reporter.consumerHistogramVec + } else { + logger.Warnf("The url is not the consumer's or provider's, "+ + "so the invocation will be ignored. url: %s", url.String()) + return + } + + labels := prometheus.Labels{ + serviceKey: url.Service(), + groupKey: url.GetParam(groupKey, ""), + versionKey: url.GetParam(versionKey, ""), + methodKey: invocation.MethodName(), + timeoutKey: url.GetParam(timeoutKey, ""), + } + + costMs := float64(cost.Nanoseconds() / constant.MsToNanoRate) + sumVec.With(labels).Observe(costMs) + hisVec.With(labels).Observe(costMs) +} + +func newHistogramVec(side string) *prometheus.HistogramVec { + mc := config.GetMetricConfig() + return prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: namespace, + Subsystem: side, + Name: serviceKey + histogramSuffix, + Help: "This is the dubbo's histogram metrics", + Buckets: mc.GetHistogramBucket(), + }, + labelNames) +} + +// whether this url represents the application received the request as server +func isProvider(url common.URL) bool { + role := url.GetParam(constant.ROLE_KEY, "") + return strings.EqualFold(role, strconv.Itoa(common.PROVIDER)) +} + +// whether this url represents the application sent then request as client +func isConsumer(url common.URL) bool { + role := url.GetParam(constant.ROLE_KEY, "") + return strings.EqualFold(role, strconv.Itoa(common.CONSUMER)) +} + +// newSummaryVec create SummaryVec, the Namespace is dubbo +// the objectives is from my experience. +func newSummaryVec(side string) *prometheus.SummaryVec { + return prometheus.NewSummaryVec( + prometheus.SummaryOpts{ + Namespace: namespace, + Help: "This is the dubbo's summary metrics", + Subsystem: side, + Name: serviceKey + summarySuffix, + Objectives: map[float64]float64{ + 0.5: 0.01, + 0.75: 0.01, + 0.90: 0.005, + 0.98: 0.002, + 0.99: 0.001, + 0.999: 0.0001, + }, + }, + labelNames, + ) +} + +// newPrometheusReporter create new prometheusReporter +// it will register the metrics into prometheus +func newPrometheusReporter() metrics.Reporter { + if reporterInstance == nil { + reporterInitOnce.Do(func() { + reporterInstance = &PrometheusReporter{ + consumerSummaryVec: newSummaryVec(consumerKey), + providerSummaryVec: newSummaryVec(providerKey), + + consumerHistogramVec: newHistogramVec(consumerKey), + providerHistogramVec: newHistogramVec(providerKey), + } + prometheus.MustRegister(reporterInstance.consumerSummaryVec, reporterInstance.providerSummaryVec, + reporterInstance.consumerHistogramVec, reporterInstance.providerHistogramVec) + }) + } + return reporterInstance +} diff --git a/metrics/prometheus/reporter_test.go b/metrics/prometheus/reporter_test.go new file mode 100644 index 0000000000000000000000000000000000000000..0cb7d09a2c8e71fb88b54789c8eb3ee2cf967fbf --- /dev/null +++ b/metrics/prometheus/reporter_test.go @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package prometheus + +import ( + "context" + "testing" + "time" +) + +import ( + "github.com/stretchr/testify/assert" +) +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/protocol" + "github.com/apache/dubbo-go/protocol/invocation" +) + +func TestPrometheusReporter_Report(t *testing.T) { + reporter := extension.GetMetricReporter(reporterName) + url, _ := common.NewURL( + "dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider" + + "&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser." + + "loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=" + + "BDTService&organization=ikurento.com&owner=ZX®istry.role=3&retries=&" + + "service.filter=echo%2Ctoken%2Caccesslog×tamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100") + invoker := protocol.NewBaseInvoker(url) + + attach := make(map[string]string, 10) + inv := invocation.NewRPCInvocation("MethodName", []interface{}{"OK", "Hello"}, attach) + + assert.False(t, isConsumer(url)) + ctx := context.Background() + reporter.Report(ctx, invoker, inv, 100*time.Millisecond, nil) + + // consumer side + url, _ = common.NewURL( + "dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider" + + "&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser." + + "loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=" + + "BDTService&organization=ikurento.com&owner=ZX®istry.role=0&retries=&" + + "service.filter=echo%2Ctoken%2Caccesslog×tamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100") + invoker = protocol.NewBaseInvoker(url) + reporter.Report(ctx, invoker, inv, 100*time.Millisecond, nil) + + // invalid role + url, _ = common.NewURL( + "dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider" + + "&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser." + + "loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name=" + + "BDTService&organization=ikurento.com&owner=ZX®istry.role=9&retries=&" + + "service.filter=echo%2Ctoken%2Caccesslog×tamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100") + invoker = protocol.NewBaseInvoker(url) + reporter.Report(ctx, invoker, inv, 100*time.Millisecond, nil) +} diff --git a/metrics/reporter.go b/metrics/reporter.go new file mode 100644 index 0000000000000000000000000000000000000000..85ef1dcdf0dad275edecc1f3a85502c1493c1395 --- /dev/null +++ b/metrics/reporter.go @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package metrics + +import ( + "context" + "time" +) +import ( + "github.com/apache/dubbo-go/protocol" +) + +const ( + NameSpace = "dubbo" +) + +// it will be use to report the invocation's duration +type Reporter interface { + // report the duration of an invocation + Report(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation, + cost time.Duration, res protocol.Result) +} diff --git a/protocol/dubbo/client_test.go b/protocol/dubbo/client_test.go index 3f8a8ee98c3b2d8b87e2d5469a18d1792578d1d6..1e0a73fac1a6cf6d4d102e5f4f6f1ba60fc4102a 100644 --- a/protocol/dubbo/client_test.go +++ b/protocol/dubbo/client_test.go @@ -210,10 +210,10 @@ func InitTest(t *testing.T) (protocol.Protocol, common.URL) { // Export proto := GetProtocol() - url, err := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/UserProvider?anyhost=true&"+ - "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+ - "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+ - "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+ + url, err := common.NewURL("dubbo://127.0.0.1:20000/UserProvider?anyhost=true&" + + "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" + + "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" + + "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" + "side=provider&timeout=3000×tamp=1556509797245&bean.name=UserProvider") assert.NoError(t, err) proto.Export(&proxy_factory.ProxyInvoker{ diff --git a/protocol/dubbo/dubbo_invoker.go b/protocol/dubbo/dubbo_invoker.go index 607ef007b5302fe07ff6090a463eab96d6ae4fa9..67d1d1e7f1710aef71f63063374a848e2981b828 100644 --- a/protocol/dubbo/dubbo_invoker.go +++ b/protocol/dubbo/dubbo_invoker.go @@ -24,6 +24,7 @@ import ( ) import ( + "github.com/opentracing/opentracing-go" perrors "github.com/pkg/errors" ) @@ -72,6 +73,10 @@ func (di *DubboInvoker) Invoke(ctx context.Context, invocation protocol.Invocati inv.SetAttachments(k, v) } } + + // put the ctx into attachment + di.appendCtx(ctx, inv) + url := di.GetUrl() // async async, err := strconv.ParseBool(inv.AttachmentsByKey(constant.ASYNC_KEY, "false")) @@ -112,3 +117,17 @@ func (di *DubboInvoker) Destroy() { } }) } + +// Finally, I made the decision that I don't provide a general way to transfer the whole context +// because it could be misused. If the context contains to many key-value pairs, the performance will be much lower. +func (di *DubboInvoker) appendCtx(ctx context.Context, inv *invocation_impl.RPCInvocation) { + // inject opentracing ctx + currentSpan := opentracing.SpanFromContext(ctx) + if currentSpan != nil { + carrier := opentracing.TextMapCarrier(inv.Attachments()) + err := opentracing.GlobalTracer().Inject(currentSpan.Context(), opentracing.TextMap, carrier) + if err != nil { + logger.Errorf("Could not inject the span context into attachments: %v", err) + } + } +} diff --git a/protocol/dubbo/dubbo_invoker_test.go b/protocol/dubbo/dubbo_invoker_test.go index e360d57b8cdd61674d35a665e8ee85e03421cc8f..1a64301f8200a4264001284cca1af3f0f1e07814 100644 --- a/protocol/dubbo/dubbo_invoker_test.go +++ b/protocol/dubbo/dubbo_invoker_test.go @@ -25,6 +25,7 @@ import ( ) import ( + "github.com/opentracing/opentracing-go" "github.com/stretchr/testify/assert" ) @@ -81,6 +82,11 @@ func TestDubboInvoker_Invoke(t *testing.T) { res = invoker.Invoke(context.Background(), inv) assert.EqualError(t, res.Error(), "request need @response") + // testing appendCtx + span, ctx := opentracing.StartSpanFromContext(context.Background(), "TestOperation") + invoker.Invoke(ctx, inv) + span.Finish() + // destroy lock.Lock() proto.Destroy() diff --git a/protocol/dubbo/dubbo_protocol_test.go b/protocol/dubbo/dubbo_protocol_test.go index a6b0bc1df3cf2eb46e07c9dab149d04f62f78012..14f6868ad4a7f2bf6f549a2fbbce8234cbb4aa12 100644 --- a/protocol/dubbo/dubbo_protocol_test.go +++ b/protocol/dubbo/dubbo_protocol_test.go @@ -18,7 +18,6 @@ package dubbo import ( - "context" "testing" ) @@ -36,10 +35,10 @@ func TestDubboProtocol_Export(t *testing.T) { // Export proto := GetProtocol() srvConf = &ServerConfig{} - url, err := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+ - "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+ - "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+ - "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+ + url, err := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&" + + "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" + + "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" + + "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" + "side=provider&timeout=3000×tamp=1556509797245") assert.NoError(t, err) exporter := proto.Export(protocol.NewBaseInvoker(url)) @@ -49,7 +48,7 @@ func TestDubboProtocol_Export(t *testing.T) { assert.True(t, eq) // second service: the same path and the different version - url2, err := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+ + url2, err := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+ "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+ "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+ "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+ @@ -78,10 +77,10 @@ func TestDubboProtocol_Export(t *testing.T) { func TestDubboProtocol_Refer(t *testing.T) { // Refer proto := GetProtocol() - url, err := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+ - "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+ - "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+ - "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+ + url, err := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&" + + "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" + + "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" + + "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" + "side=provider&timeout=3000×tamp=1556509797245") assert.NoError(t, err) clientConf = &ClientConfig{} diff --git a/protocol/dubbo/listener.go b/protocol/dubbo/listener.go index 204e8a1c5d2607d3158ff4f68334a39fd1fb7861..430c4e49d81d4d5d151a545e1a130fd4ac3fbdc5 100644 --- a/protocol/dubbo/listener.go +++ b/protocol/dubbo/listener.go @@ -29,6 +29,7 @@ import ( import ( "github.com/apache/dubbo-go-hessian2" "github.com/dubbogo/getty" + "github.com/opentracing/opentracing-go" perrors "github.com/pkg/errors" ) @@ -63,9 +64,9 @@ func (s *rpcSession) GetReqNum() int32 { return atomic.LoadInt32(&s.reqNum) } -//////////////////////////////////////////// +// ////////////////////////////////////////// // RpcClientHandler -//////////////////////////////////////////// +// ////////////////////////////////////////// // RpcClientHandler ... type RpcClientHandler struct { @@ -157,9 +158,9 @@ func (h *RpcClientHandler) OnCron(session getty.Session) { h.conn.pool.rpcClient.heartbeat(session) } -//////////////////////////////////////////// +// ////////////////////////////////////////// // RpcServerHandler -//////////////////////////////////////////// +// ////////////////////////////////////////// // RpcServerHandler ... type RpcServerHandler struct { @@ -284,7 +285,10 @@ func (h *RpcServerHandler) OnMessage(session getty.Session, pkg interface{}) { args := p.Body.(map[string]interface{})["args"].([]interface{}) inv := invocation.NewRPCInvocation(p.Service.Method, args, attachments) - result := invoker.Invoke(context.Background(), inv) + + ctx := rebuildCtx(inv) + + result := invoker.Invoke(ctx, inv) if err := result.Error(); err != nil { p.Header.ResponseStatus = hessian.Response_OK p.Body = hessian.NewResponse(nil, err, result.Attachments()) @@ -327,6 +331,21 @@ func (h *RpcServerHandler) OnCron(session getty.Session) { } } +// rebuildCtx rebuild the context by attachment. +// Once we decided to transfer more context's key-value, we should change this. +// now we only support rebuild the tracing context +func rebuildCtx(inv *invocation.RPCInvocation) context.Context { + ctx := context.Background() + + // actually, if user do not use any opentracing framework, the err will not be nil. + spanCtx, err := opentracing.GlobalTracer().Extract(opentracing.TextMap, + opentracing.TextMapCarrier(inv.Attachments())) + if err == nil { + ctx = context.WithValue(ctx, constant.TRACING_REMOTE_SPAN_CTX, spanCtx) + } + return ctx +} + func reply(session getty.Session, req *DubboPackage, tp hessian.PackageType) { resp := &DubboPackage{ Header: hessian.DubboHeader{ diff --git a/protocol/dubbo/listener_test.go b/protocol/dubbo/listener_test.go new file mode 100644 index 0000000000000000000000000000000000000000..5f809814607558650e09934019db96dbb2ceeeae --- /dev/null +++ b/protocol/dubbo/listener_test.go @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dubbo + +import ( + "testing" +) + +import ( + "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go/mocktracer" + "github.com/stretchr/testify/assert" +) + +import ( + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/protocol/invocation" +) + +// test rebuild the ctx +func TestRebuildCtx(t *testing.T) { + opentracing.SetGlobalTracer(mocktracer.New()) + attach := make(map[string]string, 10) + attach[constant.VERSION_KEY] = "1.0" + attach[constant.GROUP_KEY] = "MyGroup" + inv := invocation.NewRPCInvocation("MethodName", []interface{}{"OK", "Hello"}, attach) + + // attachment doesn't contains any tracing key-value pair, + ctx := rebuildCtx(inv) + assert.NotNil(t, ctx) + assert.Nil(t, ctx.Value(constant.TRACING_REMOTE_SPAN_CTX)) + + span, ctx := opentracing.StartSpanFromContext(ctx, "Test-Client") + + opentracing.GlobalTracer().Inject(span.Context(), opentracing.TextMap, + opentracing.TextMapCarrier(inv.Attachments())) + // rebuild the context success + inv = invocation.NewRPCInvocation("MethodName", []interface{}{"OK", "Hello"}, attach) + ctx = rebuildCtx(inv) + span.Finish() + assert.NotNil(t, ctx) + assert.NotNil(t, ctx.Value(constant.TRACING_REMOTE_SPAN_CTX)) +} diff --git a/protocol/dubbo/pool.go b/protocol/dubbo/pool.go index 2df1c6935305e0d70635613f509021e5b9203833..9d381585b56ec439f8ebb8938109baf47bb502b2 100644 --- a/protocol/dubbo/pool.go +++ b/protocol/dubbo/pool.go @@ -360,6 +360,13 @@ func (p *gettyRPCClientPool) put(conn *gettyRPCClient) { return } + // check whether @conn has existed in p.conns or not. + for i := range p.conns { + if p.conns[i] == conn { + return + } + } + if len(p.conns) >= p.size { // delete @conn from client pool // p.remove(conn) diff --git a/protocol/grpc/client_test.go b/protocol/grpc/client_test.go index 7d96402782999393fc9ddf7b6c058509e342b366..56ec766f70da93bcddbcff13667a34c39deffe06 100644 --- a/protocol/grpc/client_test.go +++ b/protocol/grpc/client_test.go @@ -18,7 +18,6 @@ limitations under the License. package grpc import ( - "context" "reflect" "testing" ) @@ -47,7 +46,7 @@ func TestNewClient(t *testing.T) { go internal.InitGrpcServer() defer internal.ShutdownGrpcServer() - url, err := common.NewURL(context.Background(), "grpc://127.0.0.1:30000/GrpcGreeterImpl?accesslog=&anyhost=true&app.version=0.0.1&application=BDTService&async=false&bean.name=GrpcGreeterImpl&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&execute.limit=&execute.limit.rejected.handler=&generic=false&group=&interface=io.grpc.examples.helloworld.GreeterGrpc%24IGreeter&ip=192.168.1.106&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=1&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&module=dubbogo+say-hello+client&name=BDTService&organization=ikurento.com&owner=ZX&pid=49427&reference.filter=cshutdown®istry.role=3&remote.timestamp=1576923717&retries=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cexecute%2Cpshutdown&side=provider×tamp=1576923740&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=&warmup=100!") + url, err := common.NewURL("grpc://127.0.0.1:30000/GrpcGreeterImpl?accesslog=&anyhost=true&app.version=0.0.1&application=BDTService&async=false&bean.name=GrpcGreeterImpl&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&execute.limit=&execute.limit.rejected.handler=&generic=false&group=&interface=io.grpc.examples.helloworld.GreeterGrpc%24IGreeter&ip=192.168.1.106&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=1&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&module=dubbogo+say-hello+client&name=BDTService&organization=ikurento.com&owner=ZX&pid=49427&reference.filter=cshutdown®istry.role=3&remote.timestamp=1576923717&retries=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cexecute%2Cpshutdown&side=provider×tamp=1576923740&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=&warmup=100!") assert.Nil(t, err) cli := NewClient(url) assert.NotNil(t, cli) diff --git a/protocol/grpc/grpc_invoker_test.go b/protocol/grpc/grpc_invoker_test.go index 5d4b97051438f8404cd8fd89bcf73d24e0121868..368c1392ec03af310f93e8fc2173b8354975c99e 100644 --- a/protocol/grpc/grpc_invoker_test.go +++ b/protocol/grpc/grpc_invoker_test.go @@ -37,7 +37,7 @@ func TestInvoke(t *testing.T) { go internal.InitGrpcServer() defer internal.ShutdownGrpcServer() - url, err := common.NewURL(context.Background(), "grpc://127.0.0.1:30000/GrpcGreeterImpl?accesslog=&anyhost=true&app.version=0.0.1&application=BDTService&async=false&bean.name=GrpcGreeterImpl&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&execute.limit=&execute.limit.rejected.handler=&generic=false&group=&interface=io.grpc.examples.helloworld.GreeterGrpc%24IGreeter&ip=192.168.1.106&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=1&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&module=dubbogo+say-hello+client&name=BDTService&organization=ikurento.com&owner=ZX&pid=49427&reference.filter=cshutdown®istry.role=3&remote.timestamp=1576923717&retries=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cexecute%2Cpshutdown&side=provider×tamp=1576923740&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=&warmup=100!") + url, err := common.NewURL("grpc://127.0.0.1:30000/GrpcGreeterImpl?accesslog=&anyhost=true&app.version=0.0.1&application=BDTService&async=false&bean.name=GrpcGreeterImpl&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&execute.limit=&execute.limit.rejected.handler=&generic=false&group=&interface=io.grpc.examples.helloworld.GreeterGrpc%24IGreeter&ip=192.168.1.106&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=1&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&module=dubbogo+say-hello+client&name=BDTService&organization=ikurento.com&owner=ZX&pid=49427&reference.filter=cshutdown®istry.role=3&remote.timestamp=1576923717&retries=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cexecute%2Cpshutdown&side=provider×tamp=1576923740&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=&warmup=100!") assert.Nil(t, err) cli := NewClient(url) diff --git a/protocol/grpc/grpc_protocol_test.go b/protocol/grpc/grpc_protocol_test.go index e4629499b73c3fc4116a355bd66f440e95fe5451..d0206a0fd953e40a478c26a2298f4889d8f72771 100644 --- a/protocol/grpc/grpc_protocol_test.go +++ b/protocol/grpc/grpc_protocol_test.go @@ -18,7 +18,6 @@ limitations under the License. package grpc import ( - "context" "testing" "time" ) @@ -38,7 +37,7 @@ func TestGrpcProtocol_Export(t *testing.T) { addService() proto := GetProtocol() - url, err := common.NewURL(context.Background(), "grpc://127.0.0.1:40000/GrpcGreeterImpl?accesslog=&app.version=0.0.1&application=BDTService&bean.name=GrpcGreeterImpl&cluster=failover&environment=dev&execute.limit=&execute.limit.rejected.handler=&group=&interface=io.grpc.examples.helloworld.GreeterGrpc%24IGreeter&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=1&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&module=dubbogo+say-hello+client&name=BDTService&organization=ikurento.com&owner=ZX®istry.role=3&retries=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cexecute%2Cpshutdown×tamp=1576923717&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=&warmup=100") + url, err := common.NewURL("grpc://127.0.0.1:40000/GrpcGreeterImpl?accesslog=&app.version=0.0.1&application=BDTService&bean.name=GrpcGreeterImpl&cluster=failover&environment=dev&execute.limit=&execute.limit.rejected.handler=&group=&interface=io.grpc.examples.helloworld.GreeterGrpc%24IGreeter&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=1&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&module=dubbogo+say-hello+client&name=BDTService&organization=ikurento.com&owner=ZX®istry.role=3&retries=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cexecute%2Cpshutdown×tamp=1576923717&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=&warmup=100") assert.NoError(t, err) exporter := proto.Export(protocol.NewBaseInvoker(url)) time.Sleep(time.Second) @@ -68,7 +67,7 @@ func TestGrpcProtocol_Refer(t *testing.T) { time.Sleep(time.Second) proto := GetProtocol() - url, err := common.NewURL(context.Background(), "grpc://127.0.0.1:30000/GrpcGreeterImpl?accesslog=&anyhost=true&app.version=0.0.1&application=BDTService&async=false&bean.name=GrpcGreeterImpl&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&execute.limit=&execute.limit.rejected.handler=&generic=false&group=&interface=io.grpc.examples.helloworld.GreeterGrpc%24IGreeter&ip=192.168.1.106&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=1&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&module=dubbogo+say-hello+client&name=BDTService&organization=ikurento.com&owner=ZX&pid=49427&reference.filter=cshutdown®istry.role=3&remote.timestamp=1576923717&retries=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cexecute%2Cpshutdown&side=provider×tamp=1576923740&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=&warmup=100!") + url, err := common.NewURL("grpc://127.0.0.1:30000/GrpcGreeterImpl?accesslog=&anyhost=true&app.version=0.0.1&application=BDTService&async=false&bean.name=GrpcGreeterImpl&category=providers&cluster=failover&dubbo=dubbo-provider-golang-2.6.0&environment=dev&execute.limit=&execute.limit.rejected.handler=&generic=false&group=&interface=io.grpc.examples.helloworld.GreeterGrpc%24IGreeter&ip=192.168.1.106&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=1&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&module=dubbogo+say-hello+client&name=BDTService&organization=ikurento.com&owner=ZX&pid=49427&reference.filter=cshutdown®istry.role=3&remote.timestamp=1576923717&retries=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cexecute%2Cpshutdown&side=provider×tamp=1576923740&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=&warmup=100!") assert.NoError(t, err) invoker := proto.Refer(url) diff --git a/protocol/jsonrpc/http_test.go b/protocol/jsonrpc/http_test.go index 12ddb2dbc858aac26fb4243ecc6578b548e3af01..0cb88b36a8f330059906eb70417b6d4841020c38 100644 --- a/protocol/jsonrpc/http_test.go +++ b/protocol/jsonrpc/http_test.go @@ -56,10 +56,10 @@ func TestHTTPClient_Call(t *testing.T) { // Export proto := GetProtocol() - url, err := common.NewURL(context.Background(), "jsonrpc://127.0.0.1:20001/UserProvider?anyhost=true&"+ - "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+ - "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+ - "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+ + url, err := common.NewURL("jsonrpc://127.0.0.1:20001/UserProvider?anyhost=true&" + + "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" + + "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" + + "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" + "side=provider&timeout=3000×tamp=1556509797245&bean.name=UserProvider") assert.NoError(t, err) proto.Export(&proxy_factory.ProxyInvoker{ diff --git a/protocol/jsonrpc/jsonrpc_invoker_test.go b/protocol/jsonrpc/jsonrpc_invoker_test.go index 9eed22e67155f1b0915cbb398bcef55962258407..9e08eed2b4c61e686073a9039a605c4f73aa08c5 100644 --- a/protocol/jsonrpc/jsonrpc_invoker_test.go +++ b/protocol/jsonrpc/jsonrpc_invoker_test.go @@ -42,10 +42,10 @@ func TestJsonrpcInvoker_Invoke(t *testing.T) { // Export proto := GetProtocol() - url, err := common.NewURL(context.Background(), "jsonrpc://127.0.0.1:20001/UserProvider?anyhost=true&"+ - "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+ - "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+ - "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+ + url, err := common.NewURL("jsonrpc://127.0.0.1:20001/UserProvider?anyhost=true&" + + "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" + + "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" + + "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" + "side=provider&timeout=3000×tamp=1556509797245&bean.name=UserProvider") assert.NoError(t, err) proto.Export(&proxy_factory.ProxyInvoker{ diff --git a/protocol/jsonrpc/jsonrpc_protocol_test.go b/protocol/jsonrpc/jsonrpc_protocol_test.go index 253ab830dd85e5424811b7fd4e7e7e848adad415..c00bed12fe9fbb4937f21810cee548a25e3b1c05 100644 --- a/protocol/jsonrpc/jsonrpc_protocol_test.go +++ b/protocol/jsonrpc/jsonrpc_protocol_test.go @@ -18,7 +18,6 @@ package jsonrpc import ( - "context" "fmt" "strings" "testing" @@ -38,10 +37,10 @@ import ( func TestJsonrpcProtocol_Export(t *testing.T) { // Export proto := GetProtocol() - url, err := common.NewURL(context.Background(), "jsonrpc://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+ - "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+ - "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+ - "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+ + url, err := common.NewURL("jsonrpc://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&" + + "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" + + "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" + + "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" + "side=provider&timeout=3000×tamp=1556509797245") assert.NoError(t, err) exporter := proto.Export(protocol.NewBaseInvoker(url)) @@ -69,10 +68,10 @@ func TestJsonrpcProtocol_Export(t *testing.T) { func TestJsonrpcProtocol_Refer(t *testing.T) { // Refer proto := GetProtocol() - url, err := common.NewURL(context.Background(), "jsonrpc://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&"+ - "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&"+ - "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&"+ - "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&"+ + url, err := common.NewURL("jsonrpc://127.0.0.1:20000/com.ikurento.user.UserProvider?anyhost=true&" + + "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" + + "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" + + "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" + "side=provider&timeout=3000×tamp=1556509797245") assert.NoError(t, err) con := config.ConsumerConfig{ diff --git a/protocol/rpc_status_test.go b/protocol/rpc_status_test.go index ce2b4dc0d0fae2b271dbaeb3fdafab8858a7aa0c..ffdb3b535667f32e96c3af2be84851655abf5954 100644 --- a/protocol/rpc_status_test.go +++ b/protocol/rpc_status_test.go @@ -1,7 +1,6 @@ package protocol import ( - "context" "strconv" "testing" ) @@ -17,7 +16,7 @@ import ( func TestBeginCount(t *testing.T) { defer destroy() - url, _ := common.NewURL(context.TODO(), "dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider") + url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider") BeginCount(url, "test") urlStatus := GetURLStatus(url) methodStatus := GetMethodStatus(url, "test") @@ -31,7 +30,7 @@ func TestBeginCount(t *testing.T) { func TestEndCount(t *testing.T) { defer destroy() - url, _ := common.NewURL(context.TODO(), "dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider") + url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider") EndCount(url, "test", 100, true) urlStatus := GetURLStatus(url) methodStatus := GetMethodStatus(url, "test") @@ -44,7 +43,7 @@ func TestEndCount(t *testing.T) { func TestGetMethodStatus(t *testing.T) { defer destroy() - url, _ := common.NewURL(context.TODO(), "dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider") + url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider") status := GetMethodStatus(url, "test") assert.NotNil(t, status) assert.Equal(t, int32(0), status.total) @@ -53,7 +52,7 @@ func TestGetMethodStatus(t *testing.T) { func TestGetUrlStatus(t *testing.T) { defer destroy() - url, _ := common.NewURL(context.TODO(), "dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider") + url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider") status := GetURLStatus(url) assert.NotNil(t, status) assert.Equal(t, int32(0), status.total) @@ -62,7 +61,7 @@ func TestGetUrlStatus(t *testing.T) { func Test_beginCount0(t *testing.T) { defer destroy() - url, _ := common.NewURL(context.TODO(), "dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider") + url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider") status := GetURLStatus(url) beginCount0(status) assert.Equal(t, int32(1), status.active) @@ -71,7 +70,7 @@ func Test_beginCount0(t *testing.T) { func Test_All(t *testing.T) { defer destroy() - url, _ := common.NewURL(context.TODO(), "dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider") + url, _ := common.NewURL("dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider") request(url, "test", 100, false, true) urlStatus := GetURLStatus(url) methodStatus := GetMethodStatus(url, "test") diff --git a/registry/base_registry.go b/registry/base_registry.go new file mode 100644 index 0000000000000000000000000000000000000000..5b9aef82928d491d4b8f4dbe3caa4bd64a185dad --- /dev/null +++ b/registry/base_registry.go @@ -0,0 +1,375 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package registry + +import ( + "context" + "fmt" + "net/url" + "os" + "strconv" + "strings" + "sync" + "time" +) + +import ( + gxnet "github.com/dubbogo/gost/net" + perrors "github.com/pkg/errors" +) + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/common/logger" +) + +const ( + // RegistryConnDelay connection delay + RegistryConnDelay = 3 + // MaxWaitInterval max wait interval + MaxWaitInterval = 3 * time.Second +) + +var ( + processID = "" + localIP = "" +) + +func init() { + processID = fmt.Sprintf("%d", os.Getpid()) + localIP, _ = gxnet.GetLocalIP() +} + +/* + * -----------------------------------NOTICE--------------------------------------------- + * If there is no special case, you'd better inherit BaseRegistry and implement the + * FacadeBasedRegistry interface instead of directly implementing the Registry interface. + * -------------------------------------------------------------------------------------- + */ + +/* + * FacadeBasedRegistry interface is subclass of Registry, and it is designed for registry who want to inherit BaseRegistry. + * You have to implement the interface to inherit BaseRegistry. + */ +type FacadeBasedRegistry interface { + Registry + CreatePath(string) error + DoRegister(string, string) error + DoSubscribe(conf *common.URL) (Listener, error) + CloseAndNilClient() + CloseListener() + InitListeners() +} + +// BaseRegistry is a common logic abstract for registry. It implement Registry interface. +type BaseRegistry struct { + context context.Context + facadeBasedRegistry FacadeBasedRegistry + *common.URL + birth int64 // time of file birth, seconds since Epoch; 0 if unknown + wg sync.WaitGroup // wg+done for zk restart + done chan struct{} + cltLock sync.Mutex //ctl lock is a lock for services map + services map[string]common.URL // service name + protocol -> service config, for store the service registered +} + +// InitBaseRegistry for init some local variables and set BaseRegistry's subclass to it +func (r *BaseRegistry) InitBaseRegistry(url *common.URL, facadeRegistry FacadeBasedRegistry) Registry { + r.URL = url + r.birth = time.Now().UnixNano() + r.done = make(chan struct{}) + r.services = make(map[string]common.URL) + r.facadeBasedRegistry = facadeRegistry + return r +} + +// GetUrl for get registry's url +func (r *BaseRegistry) GetUrl() common.URL { + return *r.URL +} + +// Destroy for graceful down +func (r *BaseRegistry) Destroy() { + //first step close registry's all listeners + r.facadeBasedRegistry.CloseListener() + // then close r.done to notify other program who listen to it + close(r.done) + // wait waitgroup done (wait listeners outside close over) + r.wg.Wait() + //close registry client + r.closeRegisters() +} + +// Register implement interface registry to register +func (r *BaseRegistry) Register(conf common.URL) error { + var ( + ok bool + err error + ) + role, _ := strconv.Atoi(r.URL.GetParam(constant.ROLE_KEY, "")) + // Check if the service has been registered + r.cltLock.Lock() + _, ok = r.services[conf.Key()] + r.cltLock.Unlock() + if ok { + return perrors.Errorf("Path{%s} has been registered", conf.Key()) + } + + err = r.register(conf) + if err != nil { + return perrors.WithMessagef(err, "register(conf:%+v)", conf) + } + + r.cltLock.Lock() + r.services[conf.Key()] = conf + r.cltLock.Unlock() + logger.Debugf("(%sRegistry)Register(conf{%#v})", common.DubboRole[role], conf) + + return nil +} + +// service is for getting service path stored in url +func (r *BaseRegistry) service(c common.URL) string { + return url.QueryEscape(c.Service()) +} + +// RestartCallBack for reregister when reconnect +func (r *BaseRegistry) RestartCallBack() bool { + + // copy r.services + services := []common.URL{} + for _, confIf := range r.services { + services = append(services, confIf) + } + + flag := true + for _, confIf := range services { + err := r.register(confIf) + if err != nil { + logger.Errorf("(ZkProviderRegistry)register(conf{%#v}) = error{%#v}", + confIf, perrors.WithStack(err)) + flag = false + break + } + logger.Infof("success to re-register service :%v", confIf.Key()) + } + r.facadeBasedRegistry.InitListeners() + + return flag +} + +// register for register url to registry, include init params +func (r *BaseRegistry) register(c common.URL) error { + var ( + err error + //revision string + params url.Values + rawURL string + encodedURL string + dubboPath string + //conf config.URL + ) + params = url.Values{} + + c.RangeParams(func(key, value string) bool { + params.Add(key, value) + return true + }) + + params.Add("pid", processID) + params.Add("ip", localIP) + //params.Add("timeout", fmt.Sprintf("%d", int64(r.Timeout)/1e6)) + + role, _ := strconv.Atoi(r.URL.GetParam(constant.ROLE_KEY, "")) + switch role { + + case common.PROVIDER: + dubboPath, rawURL, err = r.providerRegistry(c, params) + case common.CONSUMER: + dubboPath, rawURL, err = r.consumerRegistry(c, params) + default: + return perrors.Errorf("@c{%v} type is not referencer or provider", c) + } + encodedURL = url.QueryEscape(rawURL) + dubboPath = strings.ReplaceAll(dubboPath, "$", "%24") + err = r.facadeBasedRegistry.DoRegister(dubboPath, encodedURL) + + if err != nil { + return perrors.WithMessagef(err, "register Node(path:%s, url:%s)", dubboPath, rawURL) + } + return nil +} + +// providerRegistry for provider role do +func (r *BaseRegistry) providerRegistry(c common.URL, params url.Values) (string, string, error) { + var ( + dubboPath string + rawURL string + err error + ) + if c.Path == "" || len(c.Methods) == 0 { + return "", "", perrors.Errorf("conf{Path:%s, Methods:%s}", c.Path, c.Methods) + } + dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), common.DubboNodes[common.PROVIDER]) + r.cltLock.Lock() + err = r.facadeBasedRegistry.CreatePath(dubboPath) + r.cltLock.Unlock() + if err != nil { + logger.Errorf("facadeBasedRegistry.CreatePath(path{%s}) = error{%#v}", dubboPath, perrors.WithStack(err)) + return "", "", perrors.WithMessagef(err, "facadeBasedRegistry.CreatePath(path:%s)", dubboPath) + } + params.Add("anyhost", "true") + + // Dubbo java consumer to start looking for the provider url,because the category does not match, + // the provider will not find, causing the consumer can not start, so we use consumers. + // DubboRole = [...]string{"consumer", "", "", "provider"} + // params.Add("category", (RoleType(PROVIDER)).Role()) + params.Add("category", (common.RoleType(common.PROVIDER)).String()) + params.Add("dubbo", "dubbo-provider-golang-"+constant.Version) + + params.Add("side", (common.RoleType(common.PROVIDER)).Role()) + + if len(c.Methods) == 0 { + params.Add("methods", strings.Join(c.Methods, ",")) + } + logger.Debugf("provider url params:%#v", params) + var host string + if c.Ip == "" { + host = localIP + ":" + c.Port + } else { + host = c.Ip + ":" + c.Port + } + + rawURL = fmt.Sprintf("%s://%s%s?%s", c.Protocol, host, c.Path, params.Encode()) + // Print your own registration service providers. + dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), (common.RoleType(common.PROVIDER)).String()) + logger.Debugf("provider path:%s, url:%s", dubboPath, rawURL) + return dubboPath, rawURL, nil +} + +// consumerRegistry for consumer role do +func (r *BaseRegistry) consumerRegistry(c common.URL, params url.Values) (string, string, error) { + var ( + dubboPath string + rawURL string + err error + ) + dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), common.DubboNodes[common.CONSUMER]) + r.cltLock.Lock() + err = r.facadeBasedRegistry.CreatePath(dubboPath) + r.cltLock.Unlock() + if err != nil { + logger.Errorf("facadeBasedRegistry.CreatePath(path{%s}) = error{%v}", dubboPath, perrors.WithStack(err)) + return "", "", perrors.WithStack(err) + } + dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), common.DubboNodes[common.PROVIDER]) + r.cltLock.Lock() + err = r.facadeBasedRegistry.CreatePath(dubboPath) + r.cltLock.Unlock() + if err != nil { + logger.Errorf("facadeBasedRegistry.CreatePath(path{%s}) = error{%v}", dubboPath, perrors.WithStack(err)) + return "", "", perrors.WithStack(err) + } + + params.Add("protocol", c.Protocol) + params.Add("category", (common.RoleType(common.CONSUMER)).String()) + params.Add("dubbo", "dubbogo-consumer-"+constant.Version) + + rawURL = fmt.Sprintf("consumer://%s%s?%s", localIP, c.Path, params.Encode()) + dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), (common.RoleType(common.CONSUMER)).String()) + + logger.Debugf("consumer path:%s, url:%s", dubboPath, rawURL) + return dubboPath, rawURL, nil +} + +// sleepWait... +func sleepWait(n int) { + wait := time.Duration((n + 1) * 2e8) + if wait > MaxWaitInterval { + wait = MaxWaitInterval + } + time.Sleep(wait) +} + +// Subscribe :subscribe from registry, event will notify by notifyListener +func (r *BaseRegistry) Subscribe(url *common.URL, notifyListener NotifyListener) { + n := 0 + for { + n++ + if !r.IsAvailable() { + logger.Warnf("event listener game over.") + return + } + + listener, err := r.facadeBasedRegistry.DoSubscribe(url) + if err != nil { + if !r.IsAvailable() { + logger.Warnf("event listener game over.") + return + } + logger.Warnf("getListener() = err:%v", perrors.WithStack(err)) + time.Sleep(time.Duration(RegistryConnDelay) * time.Second) + continue + } + + for { + if serviceEvent, err := listener.Next(); err != nil { + logger.Warnf("Selector.watch() = error{%v}", perrors.WithStack(err)) + listener.Close() + break + } else { + logger.Infof("update begin, service event: %v", serviceEvent.String()) + notifyListener.Notify(serviceEvent) + } + + } + sleepWait(n) + } +} + +// closeRegisters close and remove registry client and reset services map +func (r *BaseRegistry) closeRegisters() { + r.cltLock.Lock() + defer r.cltLock.Unlock() + logger.Infof("begin to close provider client") + // Close and remove(set to nil) the registry client + r.facadeBasedRegistry.CloseAndNilClient() + // reset the services map + r.services = nil +} + +// IsAvailable judge to is registry not closed by chan r.done +func (r *BaseRegistry) IsAvailable() bool { + select { + case <-r.done: + return false + default: + return true + } +} + +// WaitGroup open for outside add the waitgroup to add some logic before registry destroyed over(graceful down) +func (r *BaseRegistry) WaitGroup() *sync.WaitGroup { + return &r.wg +} + +// Done open for outside to listen the event of registry Destroy() called. +func (r *BaseRegistry) Done() chan struct{} { + return r.done +} diff --git a/registry/consul/utils.go b/registry/consul/utils.go index d295f644631ae63b6bdf035f71f5f104a64083e2..05ac5e76e292a2b574bd5e661bbbcca4f419fc22 100644 --- a/registry/consul/utils.go +++ b/registry/consul/utils.go @@ -18,7 +18,6 @@ package consul import ( - "context" "crypto/md5" "encoding/hex" "fmt" @@ -100,7 +99,7 @@ func retrieveURL(service *consul.ServiceEntry) (common.URL, error) { if !ok { return common.URL{}, perrors.New("retrieve url fails with no url key in service meta") } - url1, err := common.NewURL(context.Background(), url) + url1, err := common.NewURL(url) if err != nil { return common.URL{}, perrors.WithStack(err) } diff --git a/registry/directory/directory_test.go b/registry/directory/directory_test.go index b3c1d35aaa66b3437ff89807fba2df0a383921cb..8ebd130d7d1797a9d8707628d7e5920be758e389 100644 --- a/registry/directory/directory_test.go +++ b/registry/directory/directory_test.go @@ -18,7 +18,6 @@ package directory import ( - "context" "net/url" "strconv" "testing" @@ -62,7 +61,7 @@ func TestSubscribe(t *testing.T) { //} func TestSubscribe_InvalidUrl(t *testing.T) { - url, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111") + url, _ := common.NewURL("mock://127.0.0.1:1111") mockRegistry, _ := registry.NewMockRegistry(&common.URL{}) _, err := NewRegistryDirectory(&url, mockRegistry) assert.Error(t, err) @@ -72,8 +71,8 @@ func TestSubscribe_Group(t *testing.T) { extension.SetProtocol(protocolwrapper.FILTER, protocolwrapper.NewMockProtocolFilter) extension.SetCluster("mock", cluster_impl.NewMockCluster) - regurl, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111") - suburl, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000") + regurl, _ := common.NewURL("mock://127.0.0.1:1111") + suburl, _ := common.NewURL("dubbo://127.0.0.1:20000") suburl.SetParam(constant.CLUSTER_KEY, "mock") regurl.SubURL = &suburl mockRegistry, _ := registry.NewMockRegistry(&common.URL{}) @@ -124,7 +123,7 @@ func Test_List(t *testing.T) { } func Test_MergeProviderUrl(t *testing.T) { registryDirectory, mockRegistry := normalRegistryDir(true) - providerUrl, _ := common.NewURL(context.TODO(), "dubbo://0.0.0.0:20000/org.apache.dubbo-go.mockService", + providerUrl, _ := common.NewURL("dubbo://0.0.0.0:20000/org.apache.dubbo-go.mockService", common.WithParamsValue(constant.CLUSTER_KEY, "mock1"), common.WithParamsValue(constant.GROUP_KEY, "group"), common.WithParamsValue(constant.VERSION_KEY, "1.0.0")) @@ -139,7 +138,7 @@ func Test_MergeProviderUrl(t *testing.T) { func Test_MergeOverrideUrl(t *testing.T) { registryDirectory, mockRegistry := normalRegistryDir(true) - providerUrl, _ := common.NewURL(context.TODO(), "dubbo://0.0.0.0:20000/org.apache.dubbo-go.mockService", + providerUrl, _ := common.NewURL("dubbo://0.0.0.0:20000/org.apache.dubbo-go.mockService", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithParamsValue(constant.GROUP_KEY, "group"), common.WithParamsValue(constant.VERSION_KEY, "1.0.0")) @@ -147,7 +146,7 @@ func Test_MergeOverrideUrl(t *testing.T) { Loop1: for { if len(registryDirectory.cacheInvokers) > 0 { - overrideUrl, _ := common.NewURL(context.TODO(), "override://0.0.0.0:20000/org.apache.dubbo-go.mockService", + overrideUrl, _ := common.NewURL("override://0.0.0.0:20000/org.apache.dubbo-go.mockService", common.WithParamsValue(constant.CLUSTER_KEY, "mock1"), common.WithParamsValue(constant.GROUP_KEY, "group"), common.WithParamsValue(constant.VERSION_KEY, "1.0.0")) @@ -173,9 +172,8 @@ Loop1: func normalRegistryDir(noMockEvent ...bool) (*registryDirectory, *registry.MockRegistry) { extension.SetProtocol(protocolwrapper.FILTER, protocolwrapper.NewMockProtocolFilter) - url, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111") + url, _ := common.NewURL("mock://127.0.0.1:1111") suburl, _ := common.NewURL( - context.TODO(), "dubbo://127.0.0.1:20000/org.apache.dubbo-go.mockService", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithParamsValue(constant.GROUP_KEY, "group"), diff --git a/registry/etcdv3/listener.go b/registry/etcdv3/listener.go index 30e0cec67e2dca7242a6d04bab1a74cf92a7aabd..79e3ad514584937e742db4bbc993202dd6a9f5b9 100644 --- a/registry/etcdv3/listener.go +++ b/registry/etcdv3/listener.go @@ -18,7 +18,6 @@ package etcdv3 import ( - "context" "strings" ) @@ -51,7 +50,7 @@ func (l *dataListener) AddInterestedURL(url *common.URL) { func (l *dataListener) DataChange(eventType remoting.Event) bool { url := eventType.Path[strings.Index(eventType.Path, "/providers/")+len("/providers/"):] - serviceURL, err := common.NewURL(context.Background(), url) + serviceURL, err := common.NewURL(url) if err != nil { logger.Warnf("Listen NewURL(r{%s}) = error{%v}", eventType.Path, err) return false @@ -78,10 +77,10 @@ type configurationListener struct { events chan *config_center.ConfigChangeEvent } -// NewConfigurationListener ... +// NewConfigurationListener for listening the event of etcdv3. func NewConfigurationListener(reg *etcdV3Registry) *configurationListener { // add a new waiter - reg.wg.Add(1) + reg.WaitGroup().Add(1) return &configurationListener{registry: reg, events: make(chan *config_center.ConfigChangeEvent, 32)} } func (l *configurationListener) Process(configType *config_center.ConfigChangeEvent) { @@ -91,7 +90,7 @@ func (l *configurationListener) Process(configType *config_center.ConfigChangeEv func (l *configurationListener) Next() (*registry.ServiceEvent, error) { for { select { - case <-l.registry.done: + case <-l.registry.Done(): logger.Warnf("listener's etcd client connection is broken, so etcd event listener exit now.") return nil, perrors.New("listener stopped") @@ -99,7 +98,7 @@ func (l *configurationListener) Next() (*registry.ServiceEvent, error) { logger.Infof("got etcd event %#v", e) if e.ConfigType == remoting.EventTypeDel { select { - case <-l.registry.done: + case <-l.registry.Done(): logger.Warnf("update @result{%s}. But its connection to registry is invalid", e.Value) default: } @@ -110,5 +109,5 @@ func (l *configurationListener) Next() (*registry.ServiceEvent, error) { } } func (l *configurationListener) Close() { - l.registry.wg.Done() + l.registry.WaitGroup().Done() } diff --git a/registry/etcdv3/listener_test.go b/registry/etcdv3/listener_test.go index c064f99c6c4b447a6c81093b87d99e1d1ba6d17a..928e3fa83d4a19869903d3aaee1691c298b031b2 100644 --- a/registry/etcdv3/listener_test.go +++ b/registry/etcdv3/listener_test.go @@ -18,10 +18,10 @@ package etcdv3 import ( - "context" - "github.com/apache/dubbo-go/config_center" "testing" "time" + + "github.com/apache/dubbo-go/config_center" ) import ( @@ -73,7 +73,7 @@ func (suite *RegistryTestSuite) TestDataChange() { t := suite.T() listener := NewRegistryDataListener(&MockDataListener{}) - url, _ := common.NewURL(context.Background(), "jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100") + url, _ := common.NewURL("jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100") listener.AddInterestedURL(&url) if !listener.DataChange(remoting.Event{Path: "/dubbo/com.ikurento.user.UserProvider/providers/jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-2.6.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100"}) { t.Fatal("data change not ok") diff --git a/registry/etcdv3/registry.go b/registry/etcdv3/registry.go index 0320579286a9bdb4cecadb50430c850d6ae3e61f..e1c25768119ea7d7122b9aa22a5f881db44bafd9 100644 --- a/registry/etcdv3/registry.go +++ b/registry/etcdv3/registry.go @@ -19,17 +19,13 @@ package etcdv3 import ( "fmt" - "net/url" - "os" "path" - "strconv" "strings" "sync" "time" ) import ( - gxnet "github.com/dubbogo/gost/net" perrors "github.com/pkg/errors" ) @@ -42,39 +38,23 @@ import ( "github.com/apache/dubbo-go/remoting/etcdv3" ) -var ( - processID = "" - localIP = "" -) - const ( // Name module name Name = "etcdv3" - // RegistryConnDelay ... - RegistryConnDelay = 3 ) func init() { - processID = fmt.Sprintf("%d", os.Getpid()) - localIP, _ = gxnet.GetLocalIP() extension.SetRegistry(Name, newETCDV3Registry) } type etcdV3Registry struct { - *common.URL - birth int64 // time of file birth, seconds since Epoch; 0 if unknown - - cltLock sync.Mutex - client *etcdv3.Client - services map[string]common.URL // service name + protocol -> service config - + registry.BaseRegistry + cltLock sync.Mutex + client *etcdv3.Client listenerLock sync.Mutex listener *etcdv3.EventListener dataListener *dataListener configListener *configurationListener - - wg sync.WaitGroup // wg+done for etcd client restart - done chan struct{} } // Client get the etcdv3 client @@ -92,38 +72,6 @@ func (r *etcdV3Registry) ClientLock() *sync.Mutex { return &r.cltLock } -//WaitGroup return the wait group handle -func (r *etcdV3Registry) WaitGroup() *sync.WaitGroup { - return &r.wg -} - -// GetDone return the done channel -func (r *etcdV3Registry) GetDone() chan struct{} { - return r.done -} - -//RestartCallBack restart callback -func (r *etcdV3Registry) RestartCallBack() bool { - - services := []common.URL{} - for _, confIf := range r.services { - services = append(services, confIf) - } - - flag := true - for _, confIf := range services { - err := r.Register(confIf) - if err != nil { - logger.Errorf("(etcdV3ProviderRegistry)register(conf{%#v}) = error{%#v}", - confIf, perrors.WithStack(err)) - flag = false - break - } - logger.Infof("success to re-register service :%v", confIf.Key()) - } - return flag -} - func newETCDV3Registry(url *common.URL) (registry.Registry, error) { timeout, err := time.ParseDuration(url.GetParam(constant.REGISTRY_TIMEOUT_KEY, constant.DEFAULT_REG_TIMEOUT)) @@ -135,12 +83,9 @@ func newETCDV3Registry(url *common.URL) (registry.Registry, error) { logger.Infof("etcd address is: %v, timeout is: %s", url.Location, timeout.String()) - r := &etcdV3Registry{ - URL: url, - birth: time.Now().UnixNano(), - done: make(chan struct{}), - services: make(map[string]common.URL), - } + r := &etcdV3Registry{} + + r.InitBaseRegistry(url, r) if err := etcdv3.ValidateClient( r, @@ -150,93 +95,37 @@ func newETCDV3Registry(url *common.URL) (registry.Registry, error) { ); err != nil { return nil, err } + r.WaitGroup().Add(1) //etcdv3 client start successful, then wg +1 - r.wg.Add(1) go etcdv3.HandleClientRestart(r) - r.listener = etcdv3.NewEventListener(r.client) - r.configListener = NewConfigurationListener(r) - r.dataListener = NewRegistryDataListener(r.configListener) + r.InitListeners() return r, nil } -// GetUrl get registry url -func (r *etcdV3Registry) GetUrl() common.URL { - return *r.URL -} - -// IsAvailable check the register client is available -func (r *etcdV3Registry) IsAvailable() bool { - - select { - case <-r.done: - return false - default: - return true - } +func (r *etcdV3Registry) InitListeners() { + r.listener = etcdv3.NewEventListener(r.client) + r.configListener = NewConfigurationListener(r) + r.dataListener = NewRegistryDataListener(r.configListener) } -// Destroy destroy client -func (r *etcdV3Registry) Destroy() { - - if r.configListener != nil { - r.configListener.Close() - } - r.stop() +func (r *etcdV3Registry) DoRegister(root string, node string) error { + return r.client.Create(path.Join(root, node), "") } -func (r *etcdV3Registry) stop() { - - close(r.done) - - // close current client +func (r *etcdV3Registry) CloseAndNilClient() { r.client.Close() - - r.cltLock.Lock() r.client = nil - r.services = nil - r.cltLock.Unlock() } -// Register ... -func (r *etcdV3Registry) Register(svc common.URL) error { - - role, err := strconv.Atoi(r.URL.GetParam(constant.ROLE_KEY, "")) - if err != nil { - return perrors.WithMessage(err, "get registry role") - } - - r.cltLock.Lock() - if _, ok := r.services[svc.Key()]; ok { - r.cltLock.Unlock() - return perrors.New(fmt.Sprintf("Path{%s} has been registered", svc.Path)) - } - r.cltLock.Unlock() - - switch role { - case common.PROVIDER: - logger.Debugf("(provider register )Register(conf{%#v})", svc) - if err := r.registerProvider(svc); err != nil { - return perrors.WithMessage(err, "register provider") - } - case common.CONSUMER: - logger.Debugf("(consumer register )Register(conf{%#v})", svc) - if err := r.registerConsumer(svc); err != nil { - return perrors.WithMessage(err, "register consumer") - } - default: - return perrors.New(fmt.Sprintf("unknown role %d", role)) +func (r *etcdV3Registry) CloseListener() { + if r.configListener != nil { + r.configListener.Close() } - - r.cltLock.Lock() - r.services[svc.Key()] = svc - r.cltLock.Unlock() - return nil } -func (r *etcdV3Registry) createDirIfNotExist(k string) error { - +func (r *etcdV3Registry) CreatePath(k string) error { var tmpPath string for _, str := range strings.Split(k, "/")[1:] { tmpPath = path.Join(tmpPath, "/", str) @@ -248,89 +137,7 @@ func (r *etcdV3Registry) createDirIfNotExist(k string) error { return nil } -func (r *etcdV3Registry) registerConsumer(svc common.URL) error { - - consumersNode := fmt.Sprintf("/dubbo/%s/%s", svc.Service(), common.DubboNodes[common.CONSUMER]) - if err := r.createDirIfNotExist(consumersNode); err != nil { - logger.Errorf("etcd client create path %s: %v", consumersNode, err) - return perrors.WithMessage(err, "etcd create consumer nodes") - } - providersNode := fmt.Sprintf("/dubbo/%s/%s", svc.Service(), common.DubboNodes[common.PROVIDER]) - if err := r.createDirIfNotExist(providersNode); err != nil { - return perrors.WithMessage(err, "create provider node") - } - - params := url.Values{} - - params.Add("protocol", svc.Protocol) - - params.Add("category", (common.RoleType(common.CONSUMER)).String()) - params.Add("dubbo", "dubbogo-consumer-"+constant.Version) - - encodedURL := url.QueryEscape(fmt.Sprintf("consumer://%s%s?%s", localIP, svc.Path, params.Encode())) - dubboPath := fmt.Sprintf("/dubbo/%s/%s", svc.Service(), (common.RoleType(common.CONSUMER)).String()) - if err := r.client.Create(path.Join(dubboPath, encodedURL), ""); err != nil { - return perrors.WithMessagef(err, "create k/v in etcd (path:%s, url:%s)", dubboPath, encodedURL) - } - - return nil -} - -func (r *etcdV3Registry) registerProvider(svc common.URL) error { - - if len(svc.Path) == 0 || len(svc.Methods) == 0 { - return perrors.New(fmt.Sprintf("service path %s or service method %s", svc.Path, svc.Methods)) - } - - var ( - urlPath string - encodedURL string - dubboPath string - ) - - providersNode := fmt.Sprintf("/dubbo/%s/%s", svc.Service(), common.DubboNodes[common.PROVIDER]) - if err := r.createDirIfNotExist(providersNode); err != nil { - return perrors.WithMessage(err, "create provider node") - } - - params := url.Values{} - - svc.RangeParams(func(key, value string) bool { - params[key] = []string{value} - return true - }) - params.Add("pid", processID) - params.Add("ip", localIP) - params.Add("anyhost", "true") - params.Add("category", (common.RoleType(common.PROVIDER)).String()) - params.Add("dubbo", "dubbo-provider-golang-"+constant.Version) - params.Add("side", (common.RoleType(common.PROVIDER)).Role()) - - if len(svc.Methods) == 0 { - params.Add("methods", strings.Join(svc.Methods, ",")) - } - - logger.Debugf("provider url params:%#v", params) - var host string - if len(svc.Ip) == 0 { - host = localIP + ":" + svc.Port - } else { - host = svc.Ip + ":" + svc.Port - } - - urlPath = svc.Path - - encodedURL = url.QueryEscape(fmt.Sprintf("%s://%s%s?%s", svc.Protocol, host, urlPath, params.Encode())) - dubboPath = fmt.Sprintf("/dubbo/%s/%s", svc.Service(), (common.RoleType(common.PROVIDER)).String()) - - if err := r.client.Create(path.Join(dubboPath, encodedURL), ""); err != nil { - return perrors.WithMessagef(err, "create k/v in etcd (path:%s, url:%s)", dubboPath, encodedURL) - } - - return nil -} - -func (r *etcdV3Registry) subscribe(svc *common.URL) (registry.Listener, error) { +func (r *etcdV3Registry) DoSubscribe(svc *common.URL) (registry.Listener, error) { var ( configListener *configurationListener @@ -363,35 +170,3 @@ func (r *etcdV3Registry) subscribe(svc *common.URL) (registry.Listener, error) { return configListener, nil } - -//Subscribe from registry -func (r *etcdV3Registry) Subscribe(url *common.URL, notifyListener registry.NotifyListener) { - for { - if !r.IsAvailable() { - logger.Warnf("event listener game over.") - return - } - - listener, err := r.subscribe(url) - if err != nil { - if !r.IsAvailable() { - logger.Warnf("event listener game over.") - return - } - logger.Warnf("getListener() = err:%v", perrors.WithStack(err)) - time.Sleep(time.Duration(RegistryConnDelay) * time.Second) - continue - } - - for { - serviceEvent, err := listener.Next() - if err != nil { - logger.Warnf("Selector.watch() = error{%v}", perrors.WithStack(err)) - listener.Close() - return - } - logger.Infof("update begin, service event: %v", serviceEvent.String()) - notifyListener.Notify(serviceEvent) - } - } -} diff --git a/registry/etcdv3/registry_test.go b/registry/etcdv3/registry_test.go index ab997b2916b09e5a6807030707b1872f955a2c4c..6e26a8f3fcbbf50592520a44b253e5abbaedb061 100644 --- a/registry/etcdv3/registry_test.go +++ b/registry/etcdv3/registry_test.go @@ -18,7 +18,6 @@ package etcdv3 import ( - "context" "strconv" "testing" "time" @@ -35,7 +34,7 @@ import ( func initRegistry(t *testing.T) *etcdV3Registry { - regurl, err := common.NewURL(context.Background(), "registry://127.0.0.1:2379", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) + regurl, err := common.NewURL("registry://127.0.0.1:2379", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) if err != nil { t.Fatal(err) } @@ -55,7 +54,7 @@ func (suite *RegistryTestSuite) TestRegister() { t := suite.T() - url, _ := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"})) + url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"})) reg := initRegistry(t) err := reg.Register(url) @@ -71,8 +70,8 @@ func (suite *RegistryTestSuite) TestRegister() { func (suite *RegistryTestSuite) TestSubscribe() { t := suite.T() - regurl, _ := common.NewURL(context.Background(), "registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) - url, _ := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"})) + regurl, _ := common.NewURL("registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) + url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"})) reg := initRegistry(t) //provider register @@ -87,7 +86,7 @@ func (suite *RegistryTestSuite) TestSubscribe() { err = reg2.Register(url) assert.NoError(t, err) - listener, err := reg2.subscribe(&url) + listener, err := reg2.DoSubscribe(&url) if err != nil { t.Fatal(err) } @@ -102,10 +101,10 @@ func (suite *RegistryTestSuite) TestSubscribe() { func (suite *RegistryTestSuite) TestConsumerDestory() { t := suite.T() - url, _ := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"})) + url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"})) reg := initRegistry(t) - _, err := reg.subscribe(&url) + _, err := reg.DoSubscribe(&url) if err != nil { t.Fatal(err) } @@ -122,7 +121,7 @@ func (suite *RegistryTestSuite) TestProviderDestory() { t := suite.T() reg := initRegistry(t) - url, _ := common.NewURL(context.Background(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"})) + url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"})) err := reg.Register(url) assert.NoError(t, err) diff --git a/registry/nacos/registry_test.go b/registry/nacos/registry_test.go index e6ab693cd3f5432fe30c2b83011cd56e44ac509f..7475b455c0dda09da65012465711ece264bb3dd5 100644 --- a/registry/nacos/registry_test.go +++ b/registry/nacos/registry_test.go @@ -18,7 +18,6 @@ package nacos import ( - "context" "encoding/json" "net/url" "strconv" @@ -36,14 +35,14 @@ import ( ) func TestNacosRegistry_Register(t *testing.T) { - regurl, _ := common.NewURL(context.TODO(), "registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) + regurl, _ := common.NewURL("registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) urlMap := url.Values{} urlMap.Set(constant.GROUP_KEY, "guangzhou-idc") urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)) urlMap.Set(constant.INTERFACE_KEY, "com.ikurento.user.UserProvider") urlMap.Set(constant.VERSION_KEY, "1.0.0") urlMap.Set(constant.CLUSTER_KEY, "mock") - url, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"})) + url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"})) reg, err := newNacosRegistry(®url) assert.Nil(t, err) @@ -65,7 +64,7 @@ func TestNacosRegistry_Register(t *testing.T) { } func TestNacosRegistry_Subscribe(t *testing.T) { - regurl, _ := common.NewURL(context.TODO(), "registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) + regurl, _ := common.NewURL("registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) urlMap := url.Values{} urlMap.Set(constant.GROUP_KEY, "guangzhou-idc") urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)) @@ -73,7 +72,7 @@ func TestNacosRegistry_Subscribe(t *testing.T) { urlMap.Set(constant.VERSION_KEY, "1.0.0") urlMap.Set(constant.CLUSTER_KEY, "mock") urlMap.Set(constant.NACOS_PATH_KEY, "") - url, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"})) + url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"})) reg, _ := newNacosRegistry(®url) err := reg.Register(url) @@ -103,7 +102,7 @@ func TestNacosRegistry_Subscribe(t *testing.T) { } func TestNacosRegistry_Subscribe_del(t *testing.T) { - regurl, _ := common.NewURL(context.TODO(), "registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) + regurl, _ := common.NewURL("registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) urlMap := url.Values{} urlMap.Set(constant.GROUP_KEY, "guangzhou-idc") urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)) @@ -111,8 +110,8 @@ func TestNacosRegistry_Subscribe_del(t *testing.T) { urlMap.Set(constant.VERSION_KEY, "2.0.0") urlMap.Set(constant.CLUSTER_KEY, "mock") urlMap.Set(constant.NACOS_PATH_KEY, "") - url1, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"})) - url2, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.2:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"})) + url1, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"})) + url2, _ := common.NewURL("dubbo://127.0.0.2:20000/com.ikurento.user.UserProvider", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"})) reg, _ := newNacosRegistry(®url) err := reg.Register(url1) @@ -169,7 +168,7 @@ func TestNacosRegistry_Subscribe_del(t *testing.T) { } func TestNacosListener_Close(t *testing.T) { - regurl, _ := common.NewURL(context.TODO(), "registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) + regurl, _ := common.NewURL("registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) urlMap := url.Values{} urlMap.Set(constant.GROUP_KEY, "guangzhou-idc") urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)) @@ -177,7 +176,7 @@ func TestNacosListener_Close(t *testing.T) { urlMap.Set(constant.VERSION_KEY, "1.0.0") urlMap.Set(constant.CLUSTER_KEY, "mock") urlMap.Set(constant.NACOS_PATH_KEY, "") - url1, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider2", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"})) + url1, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider2", common.WithParams(urlMap), common.WithMethods([]string{"GetUser", "AddUser"})) reg, _ := newNacosRegistry(®url) listener, err := reg.(*nacosRegistry).subscribe(&url1) assert.Nil(t, err) diff --git a/registry/protocol/protocol_test.go b/registry/protocol/protocol_test.go index 0c19da59df6e4fd2f663f9e8d541165fe26c3ffa..de57a0afa7529dd5c77c1fe5440b336cdd212fca 100644 --- a/registry/protocol/protocol_test.go +++ b/registry/protocol/protocol_test.go @@ -18,7 +18,6 @@ package protocol import ( - "context" "testing" "time" ) @@ -51,9 +50,8 @@ func referNormal(t *testing.T, regProtocol *registryProtocol) { extension.SetProtocol(protocolwrapper.FILTER, protocolwrapper.NewMockProtocolFilter) extension.SetCluster("mock", cluster.NewMockCluster) - url, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111") + url, _ := common.NewURL("mock://127.0.0.1:1111") suburl, _ := common.NewURL( - context.TODO(), "dubbo://127.0.0.1:20000//", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), ) @@ -76,9 +74,8 @@ func TestRefer(t *testing.T) { func TestMultiRegRefer(t *testing.T) { regProtocol := newRegistryProtocol() referNormal(t, regProtocol) - url2, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:2222") + url2, _ := common.NewURL("mock://127.0.0.1:2222") suburl2, _ := common.NewURL( - context.TODO(), "dubbo://127.0.0.1:20000//", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), ) @@ -98,9 +95,8 @@ func TestOneRegRefer(t *testing.T) { regProtocol := newRegistryProtocol() referNormal(t, regProtocol) - url2, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111") + url2, _ := common.NewURL("mock://127.0.0.1:1111") suburl2, _ := common.NewURL( - context.TODO(), "dubbo://127.0.0.1:20000//", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), ) @@ -120,9 +116,8 @@ func exporterNormal(t *testing.T, regProtocol *registryProtocol) *common.URL { extension.SetProtocol("registry", GetProtocol) extension.SetRegistry("mock", registry.NewMockRegistry) extension.SetProtocol(protocolwrapper.FILTER, protocolwrapper.NewMockProtocolFilter) - url, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111") + url, _ := common.NewURL("mock://127.0.0.1:1111") suburl, _ := common.NewURL( - context.TODO(), "dubbo://127.0.0.1:20000/org.apache.dubbo-go.mockService", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithParamsValue(constant.GROUP_KEY, "group"), @@ -148,9 +143,8 @@ func TestMultiRegAndMultiProtoExporter(t *testing.T) { regProtocol := newRegistryProtocol() exporterNormal(t, regProtocol) - url2, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:2222") + url2, _ := common.NewURL("mock://127.0.0.1:2222") suburl2, _ := common.NewURL( - context.TODO(), "jsonrpc://127.0.0.1:20000//", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), ) @@ -178,9 +172,8 @@ func TestOneRegAndProtoExporter(t *testing.T) { regProtocol := newRegistryProtocol() exporterNormal(t, regProtocol) - url2, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111") + url2, _ := common.NewURL("mock://127.0.0.1:1111") suburl2, _ := common.NewURL( - context.TODO(), "dubbo://127.0.0.1:20000/org.apache.dubbo-go.mockService", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithParamsValue(constant.GROUP_KEY, "group"), @@ -242,7 +235,6 @@ func TestExportWithOverrideListener(t *testing.T) { return } overrideUrl, _ := common.NewURL( - context.Background(), "override://0:0:0:0/org.apache.dubbo-go.mockService?cluster=mock1&&group=group&&version=1.0.0", ) event := ®istry.ServiceEvent{Action: remoting.EventTypeAdd, Service: overrideUrl} @@ -256,7 +248,7 @@ func TestExportWithOverrideListener(t *testing.T) { func TestExportWithServiceConfig(t *testing.T) { extension.SetDefaultConfigurator(configurator.NewMockConfigurator) - ccUrl, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111") + ccUrl, _ := common.NewURL("mock://127.0.0.1:1111") dc, _ := (&config_center.MockDynamicConfigurationFactory{}).GetDynamicConfiguration(&ccUrl) common_cfg.GetEnvInstance().SetDynamicConfiguration(dc) regProtocol := newRegistryProtocol() @@ -275,7 +267,7 @@ func TestExportWithServiceConfig(t *testing.T) { func TestExportWithApplicationConfig(t *testing.T) { extension.SetDefaultConfigurator(configurator.NewMockConfigurator) - ccUrl, _ := common.NewURL(context.TODO(), "mock://127.0.0.1:1111") + ccUrl, _ := common.NewURL("mock://127.0.0.1:1111") dc, _ := (&config_center.MockDynamicConfigurationFactory{}).GetDynamicConfiguration(&ccUrl) common_cfg.GetEnvInstance().SetDynamicConfiguration(dc) regProtocol := newRegistryProtocol() diff --git a/registry/registry.go b/registry/registry.go index 863e781ac7bfa1c09561a6a4ab59c7f7a14e89d2..d673864700e6ba99e8f0283247d53760b85598aa 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -21,6 +21,12 @@ import ( "github.com/apache/dubbo-go/common" ) +/* + * -----------------------------------NOTICE--------------------------------------------- + * If there is no special case, you'd better inherit BaseRegistry and implement the + * FacadeBasedRegistry interface instead of directly implementing the Registry interface. + * -------------------------------------------------------------------------------------- + */ // Registry Extension - Registry type Registry interface { common.Node diff --git a/registry/zookeeper/listener.go b/registry/zookeeper/listener.go index 0105087751f5e819fce245a4617e005a3bfaafd6..588e0c519288ed32a2453fac87d226b41d4a5194 100644 --- a/registry/zookeeper/listener.go +++ b/registry/zookeeper/listener.go @@ -18,7 +18,6 @@ package zookeeper import ( - "context" "strings" "sync" ) @@ -61,7 +60,7 @@ func (l *RegistryDataListener) DataChange(eventType remoting.Event) bool { return false } url := eventType.Path[index+len("/providers/"):] - serviceURL, err := common.NewURL(context.TODO(), url) + serviceURL, err := common.NewURL(url) if err != nil { logger.Errorf("Listen NewURL(r{%s}) = error{%v} eventType.Path={%v}", url, err, eventType.Path) return false @@ -85,9 +84,9 @@ type RegistryConfigurationListener struct { closeOnce sync.Once } -// NewRegistryConfigurationListener ... +// NewRegistryConfigurationListener for listening the event of zk. func NewRegistryConfigurationListener(client *zk.ZookeeperClient, reg *zkRegistry) *RegistryConfigurationListener { - reg.wg.Add(1) + reg.WaitGroup().Add(1) return &RegistryConfigurationListener{client: client, registry: reg, events: make(chan *config_center.ConfigChangeEvent, 32), isClosed: false} } @@ -104,7 +103,7 @@ func (l *RegistryConfigurationListener) Next() (*registry.ServiceEvent, error) { logger.Warnf("listener's zk client connection is broken, so zk event listener exit now.") return nil, perrors.New("listener stopped") - case <-l.registry.done: + case <-l.registry.Done(): logger.Warnf("zk consumer register has quit, so zk event listener exit now.") return nil, perrors.New("listener stopped") @@ -127,7 +126,7 @@ func (l *RegistryConfigurationListener) Close() { // ensure that the listener will be closed at most once. l.closeOnce.Do(func() { l.isClosed = true - l.registry.wg.Done() + l.registry.WaitGroup().Done() }) } diff --git a/registry/zookeeper/listener_test.go b/registry/zookeeper/listener_test.go index 615a4bb16a7c5cc3f3e968db24e6bd05ecfdae2a..1a76b29a6f64e0329b289ce50218032a25f6f5cd 100644 --- a/registry/zookeeper/listener_test.go +++ b/registry/zookeeper/listener_test.go @@ -18,7 +18,6 @@ package zookeeper import ( - "context" "testing" ) @@ -34,7 +33,7 @@ import ( func Test_DataChange(t *testing.T) { listener := NewRegistryDataListener(&MockDataListener{}) - url, _ := common.NewURL(context.TODO(), "jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-1.3.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100") + url, _ := common.NewURL("jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-1.3.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100") listener.AddInterestedURL(&url) int := listener.DataChange(remoting.Event{Path: "/dubbo/com.ikurento.user.UserProvider/providers/jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-1.3.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100"}) assert.Equal(t, true, int) diff --git a/registry/zookeeper/registry.go b/registry/zookeeper/registry.go index ebd63694b7772715c1f6140b12389bfa526d21c6..f4e53dcc4219d947fea93a10bccc420811afd2b9 100644 --- a/registry/zookeeper/registry.go +++ b/registry/zookeeper/registry.go @@ -18,20 +18,16 @@ package zookeeper import ( - "context" "fmt" "net/url" - "os" - "strconv" "strings" "sync" "time" ) import ( - gxnet "github.com/dubbogo/gost/net" + "github.com/dubbogo/go-zookeeper/zk" perrors "github.com/pkg/errors" - "github.com/samuel/go-zookeeper/zk" ) import ( @@ -46,21 +42,9 @@ import ( const ( // RegistryZkClient zk client name RegistryZkClient = "zk registry" - // RegistryConnDelay connection delay - RegistryConnDelay = 3 - // MaxWaitInterval max wait interval - MaxWaitInterval = 3 * time.Second -) - -var ( - processID = "" - localIP = "" ) func init() { - processID = fmt.Sprintf("%d", os.Getpid()) - localIP, _ = gxnet.GetLocalIP() - //plugins.PluggableRegistries["zookeeper"] = newZkRegistry extension.SetRegistry("zookeeper", newZkRegistry) } @@ -69,20 +53,13 @@ func init() { ///////////////////////////////////// type zkRegistry struct { - context context.Context - *common.URL - birth int64 // time of file birth, seconds since Epoch; 0 if unknown - wg sync.WaitGroup // wg+done for zk restart - done chan struct{} - - cltLock sync.Mutex - client *zookeeper.ZookeeperClient - services map[string]common.URL // service name + protocol -> service config - + registry.BaseRegistry + client *zookeeper.ZookeeperClient listenerLock sync.Mutex listener *zookeeper.ZkEventListener dataListener *RegistryDataListener configListener *RegistryConfigurationListener + cltLock sync.Mutex //for provider zkPath map[string]int // key = protocol://ip:port/interface } @@ -92,21 +69,17 @@ func newZkRegistry(url *common.URL) (registry.Registry, error) { err error r *zkRegistry ) - r = &zkRegistry{ - URL: url, - birth: time.Now().UnixNano(), - done: make(chan struct{}), - services: make(map[string]common.URL), - zkPath: make(map[string]int), + zkPath: make(map[string]int), } + r.InitBaseRegistry(url, r) err = zookeeper.ValidateZookeeperClient(r, zookeeper.WithZkName(RegistryZkClient)) if err != nil { return nil, err } + r.WaitGroup().Add(1) //zk client start successful, then wg +1 - r.wg.Add(1) go zookeeper.HandleClientRestart(r) r.listener = zookeeper.NewZkEventListener(r.client) @@ -133,27 +106,41 @@ func newMockZkRegistry(url *common.URL, opts ...zookeeper.Option) (*zk.TestClust ) r = &zkRegistry{ - URL: url, - birth: time.Now().UnixNano(), - done: make(chan struct{}), - services: make(map[string]common.URL), - zkPath: make(map[string]int), + zkPath: make(map[string]int), } - + r.InitBaseRegistry(url, r) c, r.client, _, err = zookeeper.NewMockZookeeperClient("test", 15*time.Second, opts...) if err != nil { return nil, nil, err } - r.wg.Add(1) + r.WaitGroup().Add(1) //zk client start successful, then wg +1 go zookeeper.HandleClientRestart(r) + r.InitListeners() + return c, r, nil +} +func (r *zkRegistry) InitListeners() { r.listener = zookeeper.NewZkEventListener(r.client) r.configListener = NewRegistryConfigurationListener(r.client, r) r.dataListener = NewRegistryDataListener(r.configListener) +} - return c, r, nil +func (r *zkRegistry) CreatePath(path string) error { + return r.ZkClient().Create(path) +} + +func (r *zkRegistry) DoRegister(root string, node string) error { + return r.registerTempZookeeperNode(root, node) +} + +func (r *zkRegistry) DoSubscribe(conf *common.URL) (registry.Listener, error) { + return r.getListener(conf) } +func (r *zkRegistry) CloseAndNilClient() { + r.client.Close() + r.client = nil +} func (r *zkRegistry) ZkClient() *zookeeper.ZookeeperClient { return r.client } @@ -166,222 +153,10 @@ func (r *zkRegistry) ZkClientLock() *sync.Mutex { return &r.cltLock } -func (r *zkRegistry) WaitGroup() *sync.WaitGroup { - return &r.wg -} - -func (r *zkRegistry) GetDone() chan struct{} { - return r.done -} - -func (r *zkRegistry) GetUrl() common.URL { - return *r.URL -} - -func (r *zkRegistry) Destroy() { +func (r *zkRegistry) CloseListener() { if r.configListener != nil { r.configListener.Close() } - close(r.done) - r.wg.Wait() - r.closeRegisters() -} - -func (r *zkRegistry) RestartCallBack() bool { - - // copy r.services - services := []common.URL{} - for _, confIf := range r.services { - services = append(services, confIf) - } - - flag := true - for _, confIf := range services { - err := r.register(confIf) - if err != nil { - logger.Errorf("(ZkProviderRegistry)register(conf{%#v}) = error{%#v}", - confIf, perrors.WithStack(err)) - flag = false - break - } - logger.Infof("success to re-register service :%v", confIf.Key()) - } - r.listener = zookeeper.NewZkEventListener(r.client) - r.configListener = NewRegistryConfigurationListener(r.client, r) - r.dataListener = NewRegistryDataListener(r.configListener) - - return flag -} - -func (r *zkRegistry) Register(conf common.URL) error { - var ( - ok bool - err error - ) - role, _ := strconv.Atoi(r.URL.GetParam(constant.ROLE_KEY, "")) - switch role { - case common.CONSUMER: - r.cltLock.Lock() - _, ok = r.services[conf.Key()] - r.cltLock.Unlock() - if ok { - return perrors.Errorf("Path{%s} has been registered", conf.Path) - } - - err = r.register(conf) - if err != nil { - return perrors.WithStack(err) - } - - r.cltLock.Lock() - r.services[conf.Key()] = conf - r.cltLock.Unlock() - logger.Debugf("(consumerZkConsumerRegistry)Register(conf{%#v})", conf) - - case common.PROVIDER: - - // Check if the service has been registered - r.cltLock.Lock() - // Note the difference between consumer and consumerZookeeperRegistry (consumer use conf.Path). - // Because the consumer wants to provide monitoring functions for the selector, - // the provider allows multiple groups or versions of the same service to be registered. - _, ok = r.services[conf.Key()] - r.cltLock.Unlock() - if ok { - return perrors.Errorf("Path{%s} has been registered", conf.Key()) - } - - err = r.register(conf) - if err != nil { - return perrors.WithMessagef(err, "register(conf:%+v)", conf) - } - - r.cltLock.Lock() - r.services[conf.Key()] = conf - r.cltLock.Unlock() - - logger.Debugf("(ZkProviderRegistry)Register(conf{%#v})", conf) - } - - return nil -} - -func (r *zkRegistry) service(c common.URL) string { - return url.QueryEscape(c.Service()) -} - -func (r *zkRegistry) register(c common.URL) error { - var ( - err error - //revision string - params url.Values - rawURL string - encodedURL string - dubboPath string - //conf config.URL - ) - - err = zookeeper.ValidateZookeeperClient(r, zookeeper.WithZkName(RegistryZkClient)) - if err != nil { - return perrors.WithStack(err) - } - params = url.Values{} - - c.RangeParams(func(key, value string) bool { - params.Add(key, value) - return true - }) - - params.Add("pid", processID) - params.Add("ip", localIP) - //params.Add("timeout", fmt.Sprintf("%d", int64(r.Timeout)/1e6)) - - role, _ := strconv.Atoi(r.URL.GetParam(constant.ROLE_KEY, "")) - switch role { - - case common.PROVIDER: - - if c.Path == "" || len(c.Methods) == 0 { - return perrors.Errorf("conf{Path:%s, Methods:%s}", c.Path, c.Methods) - } - // 先创建æœåŠ¡ä¸‹é¢çš„provider node - dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), common.DubboNodes[common.PROVIDER]) - r.cltLock.Lock() - err = r.client.Create(dubboPath) - r.cltLock.Unlock() - if err != nil { - logger.Errorf("zkClient.create(path{%s}) = error{%#v}", dubboPath, perrors.WithStack(err)) - return perrors.WithMessagef(err, "zkclient.Create(path:%s)", dubboPath) - } - params.Add("anyhost", "true") - - // Dubbo java consumer to start looking for the provider url,because the category does not match, - // the provider will not find, causing the consumer can not start, so we use consumers. - // DubboRole = [...]string{"consumer", "", "", "provider"} - // params.Add("category", (RoleType(PROVIDER)).Role()) - params.Add("category", (common.RoleType(common.PROVIDER)).String()) - params.Add("dubbo", "dubbo-provider-golang-"+constant.Version) - - params.Add("side", (common.RoleType(common.PROVIDER)).Role()) - - if len(c.Methods) == 0 { - params.Add("methods", strings.Join(c.Methods, ",")) - } - logger.Debugf("provider zk url params:%#v", params) - var host string - if c.Ip == "" { - host = localIP + ":" + c.Port - } else { - host = c.Ip + ":" + c.Port - } - - rawURL = fmt.Sprintf("%s://%s%s?%s", c.Protocol, host, c.Path, params.Encode()) - encodedURL = url.QueryEscape(rawURL) - - // Print your own registration service providers. - dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), (common.RoleType(common.PROVIDER)).String()) - logger.Debugf("provider path:%s, url:%s", dubboPath, rawURL) - - case common.CONSUMER: - dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), common.DubboNodes[common.CONSUMER]) - r.cltLock.Lock() - err = r.client.Create(dubboPath) - r.cltLock.Unlock() - if err != nil { - logger.Errorf("zkClient.create(path{%s}) = error{%v}", dubboPath, perrors.WithStack(err)) - return perrors.WithStack(err) - } - dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), common.DubboNodes[common.PROVIDER]) - r.cltLock.Lock() - err = r.client.Create(dubboPath) - r.cltLock.Unlock() - if err != nil { - logger.Errorf("zkClient.create(path{%s}) = error{%v}", dubboPath, perrors.WithStack(err)) - return perrors.WithStack(err) - } - - params.Add("protocol", c.Protocol) - - params.Add("category", (common.RoleType(common.CONSUMER)).String()) - params.Add("dubbo", "dubbogo-consumer-"+constant.Version) - - rawURL = fmt.Sprintf("consumer://%s%s?%s", localIP, c.Path, params.Encode()) - encodedURL = url.QueryEscape(rawURL) - - dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), (common.RoleType(common.CONSUMER)).String()) - logger.Debugf("consumer path:%s, url:%s", dubboPath, rawURL) - - default: - return perrors.Errorf("@c{%v} type is not referencer or provider", c) - } - - dubboPath = strings.ReplaceAll(dubboPath, "$", "%24") - err = r.registerTempZookeeperNode(dubboPath, encodedURL) - - if err != nil { - return perrors.WithMessagef(err, "registerTempZookeeperNode(path:%s, url:%s)", dubboPath, rawURL) - } - return nil } func (r *zkRegistry) registerTempZookeeperNode(root string, node string) error { @@ -411,53 +186,6 @@ func (r *zkRegistry) registerTempZookeeperNode(root string, node string) error { return nil } -func (r *zkRegistry) subscribe(conf *common.URL) (registry.Listener, error) { - return r.getListener(conf) -} -func sleepWait(n int) { - wait := time.Duration((n + 1) * 2e8) - if wait > MaxWaitInterval { - wait = MaxWaitInterval - } - time.Sleep(wait) -} - -//subscribe from registry -func (r *zkRegistry) Subscribe(url *common.URL, notifyListener registry.NotifyListener) { - n := 0 - for { - n++ - if !r.IsAvailable() { - logger.Warnf("event listener game over.") - return - } - - listener, err := r.subscribe(url) - if err != nil { - if !r.IsAvailable() { - logger.Warnf("event listener game over.") - return - } - logger.Warnf("getListener() = err:%v", perrors.WithStack(err)) - time.Sleep(time.Duration(RegistryConnDelay) * time.Second) - continue - } - - for { - if serviceEvent, err := listener.Next(); err != nil { - logger.Warnf("Selector.watch() = error{%v}", perrors.WithStack(err)) - listener.Close() - break - } else { - logger.Infof("update begin, service event: %v", serviceEvent.String()) - notifyListener.Notify(serviceEvent) - } - - } - sleepWait(n) - } -} - func (r *zkRegistry) getListener(conf *common.URL) (*RegistryConfigurationListener, error) { var ( zkListener *RegistryConfigurationListener @@ -494,22 +222,3 @@ func (r *zkRegistry) getListener(conf *common.URL) (*RegistryConfigurationListen return zkListener, nil } - -func (r *zkRegistry) closeRegisters() { - r.cltLock.Lock() - defer r.cltLock.Unlock() - logger.Infof("begin to close provider zk client") - // Close the old client first to close the tmp node. - r.client.Close() - r.client = nil - r.services = nil -} - -func (r *zkRegistry) IsAvailable() bool { - select { - case <-r.done: - return false - default: - return true - } -} diff --git a/registry/zookeeper/registry_test.go b/registry/zookeeper/registry_test.go index 2c7bb9061f8accc775fa840508f4363753acbc1a..0d7623ca12a9b4e49f84ec988c796f2e913d537f 100644 --- a/registry/zookeeper/registry_test.go +++ b/registry/zookeeper/registry_test.go @@ -18,7 +18,6 @@ package zookeeper import ( - "context" "strconv" "testing" "time" @@ -35,8 +34,8 @@ import ( ) func Test_Register(t *testing.T) { - regurl, _ := common.NewURL(context.TODO(), "registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) - url, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithParamsValue("serviceid", "soa.mock"), common.WithMethods([]string{"GetUser", "AddUser"})) + regurl, _ := common.NewURL("registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) + url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithParamsValue("serviceid", "soa.mock"), common.WithMethods([]string{"GetUser", "AddUser"})) ts, reg, _ := newMockZkRegistry(®url) defer ts.Stop() @@ -47,8 +46,8 @@ func Test_Register(t *testing.T) { } func Test_Subscribe(t *testing.T) { - regurl, _ := common.NewURL(context.TODO(), "registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) - url, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"})) + regurl, _ := common.NewURL("registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) + url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"})) ts, reg, _ := newMockZkRegistry(®url) //provider register @@ -64,7 +63,7 @@ func Test_Subscribe(t *testing.T) { _, reg2, _ := newMockZkRegistry(®url, zookeeper.WithTestCluster(ts)) reg2.Register(url) - listener, _ := reg2.subscribe(&url) + listener, _ := reg2.DoSubscribe(&url) serviceEvent, _ := listener.Next() assert.NoError(t, err) @@ -76,8 +75,8 @@ func Test_Subscribe(t *testing.T) { } func Test_ConsumerDestory(t *testing.T) { - regurl, _ := common.NewURL(context.TODO(), "registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER))) - url, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"})) + regurl, _ := common.NewURL("registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER))) + url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"})) ts, reg, err := newMockZkRegistry(®url) defer ts.Stop() @@ -85,7 +84,7 @@ func Test_ConsumerDestory(t *testing.T) { assert.NoError(t, err) err = reg.Register(url) assert.NoError(t, err) - _, err = reg.subscribe(&url) + _, err = reg.DoSubscribe(&url) assert.NoError(t, err) //listener.Close() @@ -96,8 +95,8 @@ func Test_ConsumerDestory(t *testing.T) { } func Test_ProviderDestory(t *testing.T) { - regurl, _ := common.NewURL(context.TODO(), "registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) - url, _ := common.NewURL(context.TODO(), "dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"})) + regurl, _ := common.NewURL("registry://127.0.0.1:1111", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER))) + url, _ := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider", common.WithParamsValue(constant.CLUSTER_KEY, "mock"), common.WithMethods([]string{"GetUser", "AddUser"})) ts, reg, err := newMockZkRegistry(®url) defer ts.Stop() diff --git a/remoting/etcdv3/facade.go b/remoting/etcdv3/facade.go index d00620661d0faf909907d3dc7c08e999de134fee..35befc85e449ec02a6377faec300aa6b46bcc8bf 100644 --- a/remoting/etcdv3/facade.go +++ b/remoting/etcdv3/facade.go @@ -38,7 +38,7 @@ type clientFacade interface { SetClient(*Client) ClientLock() *sync.Mutex WaitGroup() *sync.WaitGroup //for wait group control, etcd client listener & etcd client container - GetDone() chan struct{} //for etcd client control + Done() chan struct{} //for etcd client control RestartCallBack() bool common.Node } @@ -55,7 +55,7 @@ func HandleClientRestart(r clientFacade) { LOOP: for { select { - case <-r.GetDone(): + case <-r.Done(): logger.Warnf("(ETCDV3ProviderRegistry)reconnectETCDV3 goroutine exit now...") break LOOP // re-register all services @@ -72,7 +72,7 @@ LOOP: failTimes = 0 for { select { - case <-r.GetDone(): + case <-r.Done(): logger.Warnf("(ETCDV3ProviderRegistry)reconnectETCDRegistry goroutine exit now...") break LOOP case <-getty.GetTimeWheel().After(timeSecondDuration(failTimes * ConnDelay)): // avoid connect frequent diff --git a/remoting/zookeeper/client.go b/remoting/zookeeper/client.go index b5f02281e9dfc5b5b6f1a289164e85d2b457d1a8..f95231b374230c93036e0fbd74aeca4ecfe57f46 100644 --- a/remoting/zookeeper/client.go +++ b/remoting/zookeeper/client.go @@ -25,8 +25,8 @@ import ( ) import ( + "github.com/dubbogo/go-zookeeper/zk" perrors "github.com/pkg/errors" - "github.com/samuel/go-zookeeper/zk" ) import ( @@ -43,6 +43,8 @@ const ( var ( errNilZkClientConn = perrors.New("zookeeperclient{conn} is nil") + errNilChildren = perrors.Errorf("has none children") + errNilNode = perrors.Errorf("node does not exist") ) // ZookeeperClient ... @@ -259,11 +261,13 @@ LOOP: logger.Warnf("zk{addr:%s} state is StateDisconnected, so close the zk client{name:%s}.", z.ZkAddrs, z.name) z.stop() z.Lock() - if z.Conn != nil { - z.Conn.Close() - z.Conn = nil - } + conn := z.Conn + z.Conn = nil z.Unlock() + if conn != nil { + conn.Close() + } + break LOOP case (int)(zk.EventNodeDataChanged), (int)(zk.EventNodeChildrenChanged): logger.Infof("zkClient{%s} get zk node changed event{path:%s}", z.name, event.Path) @@ -378,11 +382,13 @@ func (z *ZookeeperClient) Close() { z.stop() z.Wait.Wait() z.Lock() - if z.Conn != nil { - z.Conn.Close() - z.Conn = nil - } + conn := z.Conn + z.Conn = nil z.Unlock() + if conn != nil { + conn.Close() + } + logger.Warnf("zkClient{name:%s, zk addr:%s} exit now.", z.name, z.ZkAddrs) } @@ -398,10 +404,12 @@ func (z *ZookeeperClient) Create(basePath string) error { tmpPath = path.Join(tmpPath, "/", str) err = errNilZkClientConn z.Lock() - if z.Conn != nil { - _, err = z.Conn.Create(tmpPath, []byte(""), 0, zk.WorldACL(zk.PermAll)) - } + conn := z.Conn z.Unlock() + if conn != nil { + _, err = conn.Create(tmpPath, []byte(""), 0, zk.WorldACL(zk.PermAll)) + } + if err != nil { if err == zk.ErrNodeExists { logger.Infof("zk.create(\"%s\") exists\n", tmpPath) @@ -423,10 +431,11 @@ func (z *ZookeeperClient) Delete(basePath string) error { err = errNilZkClientConn z.Lock() - if z.Conn != nil { - err = z.Conn.Delete(basePath, -1) - } + conn := z.Conn z.Unlock() + if conn != nil { + err = conn.Delete(basePath, -1) + } return perrors.WithMessagef(err, "Delete(basePath:%s)", basePath) } @@ -444,10 +453,12 @@ func (z *ZookeeperClient) RegisterTemp(basePath string, node string) (string, er data = []byte("") zkPath = path.Join(basePath) + "/" + node z.Lock() - if z.Conn != nil { - tmpPath, err = z.Conn.Create(zkPath, data, zk.FlagEphemeral, zk.WorldACL(zk.PermAll)) - } + conn := z.Conn z.Unlock() + if conn != nil { + tmpPath, err = conn.Create(zkPath, data, zk.FlagEphemeral, zk.WorldACL(zk.PermAll)) + } + //if err != nil && err != zk.ErrNodeExists { if err != nil { logger.Warnf("conn.Create(\"%s\", zk.FlagEphemeral) = error(%v)\n", zkPath, perrors.WithStack(err)) @@ -467,15 +478,17 @@ func (z *ZookeeperClient) RegisterTempSeq(basePath string, data []byte) (string, err = errNilZkClientConn z.Lock() - if z.Conn != nil { - tmpPath, err = z.Conn.Create( + conn := z.Conn + z.Unlock() + if conn != nil { + tmpPath, err = conn.Create( path.Join(basePath)+"/", data, zk.FlagEphemeral|zk.FlagSequence, zk.WorldACL(zk.PermAll), ) } - z.Unlock() + logger.Debugf("zookeeperClient.RegisterTempSeq(basePath{%s}) = tempPath{%s}", basePath, tmpPath) if err != nil && err != zk.ErrNodeExists { logger.Errorf("zkClient{%s} conn.Create(\"%s\", \"%s\", zk.FlagEphemeral|zk.FlagSequence) error(%v)\n", @@ -493,30 +506,35 @@ func (z *ZookeeperClient) GetChildrenW(path string) ([]string, <-chan zk.Event, err error children []string stat *zk.Stat - event <-chan zk.Event + watcher *zk.Watcher ) err = errNilZkClientConn z.Lock() - if z.Conn != nil { - children, stat, event, err = z.Conn.ChildrenW(path) - } + conn := z.Conn z.Unlock() + if conn != nil { + children, stat, watcher, err = conn.ChildrenW(path) + } + if err != nil { + if err == zk.ErrNoChildrenForEphemerals { + return nil, nil, errNilChildren + } if err == zk.ErrNoNode { - return nil, nil, perrors.Errorf("path{%s} has none children", path) + return nil, nil, errNilNode } logger.Errorf("zk.ChildrenW(path{%s}) = error(%v)", path, err) return nil, nil, perrors.WithMessagef(err, "zk.ChildrenW(path:%s)", path) } if stat == nil { - return nil, nil, perrors.Errorf("path{%s} has none children", path) + return nil, nil, perrors.Errorf("path{%s} get stat is nil", path) } if len(children) == 0 { - return nil, nil, perrors.Errorf("path{%s} has none children", path) + return nil, nil, errNilChildren } - return children, event, nil + return children, watcher.EvtCh, nil } // GetChildren ... @@ -529,10 +547,12 @@ func (z *ZookeeperClient) GetChildren(path string) ([]string, error) { err = errNilZkClientConn z.Lock() - if z.Conn != nil { - children, stat, err = z.Conn.Children(path) - } + conn := z.Conn z.Unlock() + if conn != nil { + children, stat, err = conn.Children(path) + } + if err != nil { if err == zk.ErrNoNode { return nil, perrors.Errorf("path{%s} has none children", path) @@ -544,7 +564,7 @@ func (z *ZookeeperClient) GetChildren(path string) ([]string, error) { return nil, perrors.Errorf("path{%s} has none children", path) } if len(children) == 0 { - return nil, perrors.Errorf("path{%s} has none children", path) + return nil, errNilChildren } return children, nil @@ -553,17 +573,19 @@ func (z *ZookeeperClient) GetChildren(path string) ([]string, error) { // ExistW ... func (z *ZookeeperClient) ExistW(zkPath string) (<-chan zk.Event, error) { var ( - exist bool - err error - event <-chan zk.Event + exist bool + err error + watcher *zk.Watcher ) err = errNilZkClientConn z.Lock() - if z.Conn != nil { - exist, _, event, err = z.Conn.ExistsW(zkPath) - } + conn := z.Conn z.Unlock() + if conn != nil { + exist, _, watcher, err = conn.ExistsW(zkPath) + } + if err != nil { logger.Warnf("zkClient{%s}.ExistsW(path{%s}) = error{%v}.", z.name, zkPath, perrors.WithStack(err)) return nil, perrors.WithMessagef(err, "zk.ExistsW(path:%s)", zkPath) @@ -573,7 +595,7 @@ func (z *ZookeeperClient) ExistW(zkPath string) (<-chan zk.Event, error) { return nil, perrors.Errorf("zkClient{%s} App zk path{%s} does not exist.", z.name, zkPath) } - return event, nil + return watcher.EvtCh, nil } // GetContent ... diff --git a/remoting/zookeeper/client_test.go b/remoting/zookeeper/client_test.go index f1bd0c2cb38669ad968bd83efae166a4432c6e2d..cb41eb326be95470e39694fc5df233fdf073b905 100644 --- a/remoting/zookeeper/client_test.go +++ b/remoting/zookeeper/client_test.go @@ -24,7 +24,7 @@ import ( ) import ( - "github.com/samuel/go-zookeeper/zk" + "github.com/dubbogo/go-zookeeper/zk" "github.com/stretchr/testify/assert" ) @@ -133,3 +133,12 @@ func TestRegisterTempSeq(t *testing.T) { states := []zk.State{zk.StateConnecting, zk.StateConnected, zk.StateHasSession} verifyEventStateOrder(t, event, states, "event channel") } + +func Test_UnregisterEvent(t *testing.T) { + client := &ZookeeperClient{} + client.eventRegistry = make(map[string][]*chan struct{}) + array := []*chan struct{}{} + array = append(array, new(chan struct{})) + client.eventRegistry["test"] = array + client.UnregisterEvent("test", new(chan struct{})) +} diff --git a/remoting/zookeeper/facade.go b/remoting/zookeeper/facade.go index 18f1a049883bbd5bd7d698dc05432e93eea6ce83..055db4f716a914354d1bada653fbc0a850b615b5 100644 --- a/remoting/zookeeper/facade.go +++ b/remoting/zookeeper/facade.go @@ -35,7 +35,7 @@ type zkClientFacade interface { SetZkClient(*ZookeeperClient) ZkClientLock() *sync.Mutex WaitGroup() *sync.WaitGroup //for wait group control, zk client listener & zk client container - GetDone() chan struct{} //for zk client control + Done() chan struct{} //for zk client control RestartCallBack() bool common.Node } @@ -52,7 +52,7 @@ func HandleClientRestart(r zkClientFacade) { LOOP: for { select { - case <-r.GetDone(): + case <-r.Done(): logger.Warnf("(ZkProviderRegistry)reconnectZkRegistry goroutine exit now...") break LOOP // re-register all services @@ -68,7 +68,7 @@ LOOP: failTimes = 0 for { select { - case <-r.GetDone(): + case <-r.Done(): logger.Warnf("(ZkProviderRegistry)reconnectZkRegistry goroutine exit now...") break LOOP case <-getty.GetTimeWheel().After(timeSecondDuration(failTimes * ConnDelay)): // Prevent crazy reconnection zk. diff --git a/remoting/zookeeper/facade_test.go b/remoting/zookeeper/facade_test.go index 58e0d69dcfd9bf645c147f6e920e56ed5f3951eb..97ea775652cf82ce86388fb376832ccb7e07a205 100644 --- a/remoting/zookeeper/facade_test.go +++ b/remoting/zookeeper/facade_test.go @@ -18,13 +18,12 @@ package zookeeper import ( - "context" "sync" "testing" "time" ) import ( - "github.com/samuel/go-zookeeper/zk" + "github.com/dubbogo/go-zookeeper/zk" "github.com/stretchr/testify/assert" ) import ( @@ -55,7 +54,7 @@ func (r *mockFacade) WaitGroup() *sync.WaitGroup { return &r.wg } -func (r *mockFacade) GetDone() chan struct{} { +func (r *mockFacade) Done() chan struct{} { return r.done } @@ -79,7 +78,7 @@ func Test_Facade(t *testing.T) { ts, z, event, err := NewMockZookeeperClient("test", 15*time.Second) assert.NoError(t, err) defer ts.Stop() - url, _ := common.NewURL(context.Background(), "mock://127.0.0.1") + url, _ := common.NewURL("mock://127.0.0.1") mock := &mockFacade{client: z, URL: &url} go HandleClientRestart(mock) states := []zk.State{zk.StateConnecting, zk.StateConnected, zk.StateHasSession} diff --git a/remoting/zookeeper/listener.go b/remoting/zookeeper/listener.go index 407cd8a230d730724dc6a40c2a885723f5087d60..4493c06dc3f13d59b9388268613fe9e08a14033e 100644 --- a/remoting/zookeeper/listener.go +++ b/remoting/zookeeper/listener.go @@ -19,15 +19,14 @@ package zookeeper import ( "path" - "strings" "sync" "time" ) import ( "github.com/dubbogo/getty" + "github.com/dubbogo/go-zookeeper/zk" perrors "github.com/pkg/errors" - "github.com/samuel/go-zookeeper/zk" ) import ( @@ -111,8 +110,17 @@ func (l *ZkEventListener) handleZkNodeEvent(zkPath string, children []string, li newChildren, err := l.client.GetChildren(zkPath) if err != nil { - logger.Errorf("path{%s} child nodes changed, zk.Children() = error{%v}", zkPath, perrors.WithStack(err)) - return + if err == errNilChildren { + content, _, err := l.client.Conn.Get(zkPath) + if err != nil { + logger.Errorf("Get new node path {%v} 's content error,message is {%v}", zkPath, perrors.WithStack(err)) + } else { + listener.DataChange(remoting.Event{Path: zkPath, Action: remoting.EventTypeUpdate, Content: string(content)}) + } + + } else { + logger.Errorf("path{%s} child nodes changed, zk.Children() = error{%v}", zkPath, perrors.WithStack(err)) + } } // a node was added -- listen the new node @@ -182,7 +190,7 @@ func (l *ZkEventListener) listenDirEvent(zkPath string, listener remoting.DataLi if MaxFailTimes <= failTimes { failTimes = MaxFailTimes } - logger.Warnf("listenDirEvent(path{%s}) = error{%v}", zkPath, err) + logger.Infof("listenDirEvent(path{%s}) = error{%v}", zkPath, err) // clear the event channel CLEAR: for { @@ -193,6 +201,11 @@ func (l *ZkEventListener) listenDirEvent(zkPath string, listener remoting.DataLi } } l.client.RegisterEvent(zkPath, &event) + if err == errNilNode { + logger.Warnf("listenDirEvent(path{%s}) got errNilNode,so exit listen", zkPath) + l.client.UnregisterEvent(zkPath, &event) + return + } select { case <-getty.GetTimeWheel().After(timeSecondDuration(failTimes * ConnDelay)): l.client.UnregisterEvent(zkPath, &event) @@ -272,51 +285,6 @@ func timeSecondDuration(sec int) time.Duration { // | // --------> ListenServiceNodeEvent func (l *ZkEventListener) ListenServiceEvent(zkPath string, listener remoting.DataListener) { - var ( - err error - dubboPath string - children []string - ) - - zkPath = strings.ReplaceAll(zkPath, "$", "%24") - l.pathMapLock.Lock() - _, ok := l.pathMap[zkPath] - l.pathMapLock.Unlock() - if ok { - logger.Warnf("@zkPath %s has already been listened.", zkPath) - return - } - - l.pathMapLock.Lock() - l.pathMap[zkPath] = struct{}{} - l.pathMapLock.Unlock() - - logger.Infof("listen dubbo provider path{%s} event and wait to get all provider zk nodes", zkPath) - children, err = l.client.GetChildren(zkPath) - if err != nil { - children = nil - logger.Warnf("fail to get children of zk path{%s}", zkPath) - } - - for _, c := range children { - // listen l service node - dubboPath = path.Join(zkPath, c) - content, _, err := l.client.Conn.Get(dubboPath) - if err != nil { - logger.Errorf("Get new node path {%v} 's content error,message is {%v}", dubboPath, perrors.WithStack(err)) - } - if !listener.DataChange(remoting.Event{Path: dubboPath, Action: remoting.EventTypeAdd, Content: string(content)}) { - continue - } - logger.Infof("listen dubbo service key{%s}", dubboPath) - go func(zkPath string, listener remoting.DataListener) { - if l.ListenServiceNodeEvent(zkPath) { - listener.DataChange(remoting.Event{Path: zkPath, Action: remoting.EventTypeDel}) - } - logger.Warnf("listenSelf(zk path{%s}) goroutine exit now", zkPath) - }(dubboPath, listener) - } - logger.Infof("listen dubbo path{%s}", zkPath) go func(zkPath string, listener remoting.DataListener) { l.listenDirEvent(zkPath, listener) diff --git a/remoting/zookeeper/listener_test.go b/remoting/zookeeper/listener_test.go index aa627c7e8a53ef87fb39446b05d4001bcf18cf3f..43e9aca3f44470873c3c97ec2447bebcc57e5545 100644 --- a/remoting/zookeeper/listener_test.go +++ b/remoting/zookeeper/listener_test.go @@ -24,7 +24,7 @@ import ( "time" ) import ( - "github.com/samuel/go-zookeeper/zk" + "github.com/dubbogo/go-zookeeper/zk" "github.com/stretchr/testify/assert" ) import ( @@ -97,12 +97,11 @@ func TestListener(t *testing.T) { listener := NewZkEventListener(client) dataListener := &mockDataListener{client: client, changedData: changedData, wait: &wait} listener.ListenServiceEvent("/dubbo", dataListener) - + time.Sleep(1 * time.Second) _, err := client.Conn.Set("/dubbo/dubbo.properties", []byte(changedData), 1) assert.NoError(t, err) wait.Wait() assert.Equal(t, changedData, dataListener.eventList[1].Content) - client.Close() }