You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@dubbo.apache.org by GitBox <gi...@apache.org> on 2020/08/07 09:09:36 UTC
[GitHub] [dubbo-go] zhangshen023 opened a new pull request #701: consul service
zhangshen023 opened a new pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701
<!-- Thanks for sending a pull request!
-->
**What this PR does**:
**Which issue(s) this PR fixes**:
<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
-->
Fixes #
**Special notes for your reviewer**:
**Does this PR introduce a user-facing change?**:
<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
-->
```release-note
```
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] AlexStocks commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
AlexStocks commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r487374001
##########
File path: registry/consul/service_discovery_test.go
##########
@@ -0,0 +1,237 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "math/rand"
+ "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/common/extension"
+ "github.com/apache/dubbo-go/common/observer"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+ "github.com/apache/dubbo-go/remoting/consul"
+)
+
+var (
+ testName = "test"
+ consulCheckPassInterval = 17000
+ consulDeregisterCriticalServiceAfter = "20s"
+ consulWatchTimeout = 60000
+ registryURL = common.URL{
+ Path: "",
+ Username: "",
+ Password: "",
+ Methods: nil,
+ SubURL: nil,
Review comment:
delete the default value
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,430 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
Review comment:
add a rwlock to protect consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
Review comment:
move it above the consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
Review comment:
why u do not use lock inside this func?
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
+ if csd.consulClient == nil {
+ return nil, perrors.New("consul client is destroyed or not ready!")
+ }
+ return csd.consulClient, nil
+}
Review comment:
add a blank line btw two funcs.
##########
File path: registry/consul/service_discovery_test.go
##########
@@ -0,0 +1,237 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "math/rand"
+ "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/common/extension"
+ "github.com/apache/dubbo-go/common/observer"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+ "github.com/apache/dubbo-go/remoting/consul"
+)
+
+var (
+ testName = "test"
+ consulCheckPassInterval = 17000
+ consulDeregisterCriticalServiceAfter = "20s"
+ consulWatchTimeout = 60000
+ registryURL = common.URL{
+ Path: "",
+ Username: "",
+ Password: "",
+ Methods: nil,
+ SubURL: nil,
Review comment:
delete the default value
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,430 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
Review comment:
add a rwlock to protect consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
Review comment:
move it above the consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
Review comment:
why u do not use lock inside this func?
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
+ if csd.consulClient == nil {
+ return nil, perrors.New("consul client is destroyed or not ready!")
+ }
+ return csd.consulClient, nil
+}
Review comment:
add a blank line btw two funcs.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] AlexStocks commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
AlexStocks commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r487501931
##########
File path: registry/consul/service_discovery.go
##########
@@ -141,9 +137,10 @@ func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) e
consulClient *consul.Client
)
ins, _ := csd.buildRegisterInstance(instance)
- if consulClient, err = csd.getConsulClient(); err == nil {
- err = consulClient.Agent().ServiceRegister(ins)
+ if consulClient = csd.getConsulClient(); consulClient == nil {
+ return perrors.New("consul client is closed!")
Review comment:
var (
ConsulClientClosed = perrors.New("consul client is closed")
)
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] AlexStocks commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
AlexStocks commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r479608493
##########
File path: registry/consul/service_discovery.go
##########
@@ -223,6 +225,37 @@ func (csd *consulServiceDiscovery) GetServices() *gxset.HashSet {
}
+// encodeConsulMetadata because consul validate key strictly.
+func encodeConsulMetadata(metadata map[string]string) map[string]string {
+ if metadata == nil {
+ metadata = make(map[string]string, 1)
Review comment:
metaMap := make(map[string]string, 8)
##########
File path: registry/consul/service_discovery.go
##########
@@ -223,6 +225,37 @@ func (csd *consulServiceDiscovery) GetServices() *gxset.HashSet {
}
+// encodeConsulMetadata because consul validate key strictly.
+func encodeConsulMetadata(metadata map[string]string) map[string]string {
+ if metadata == nil {
+ metadata = make(map[string]string, 1)
+ }
+ encoder := base64.RawStdEncoding
+ for k, v := range metadata {
+ delete(metadata, k)
Review comment:
delete an map elem in its for-loop range is not a good code action. pls insert data into another map 'metaMap' instead.
##########
File path: registry/consul/service_discovery.go
##########
@@ -223,6 +225,37 @@ func (csd *consulServiceDiscovery) GetServices() *gxset.HashSet {
}
+// encodeConsulMetadata because consul validate key strictly.
+func encodeConsulMetadata(metadata map[string]string) map[string]string {
+ if metadata == nil {
+ metadata = make(map[string]string, 1)
+ }
+ encoder := base64.RawStdEncoding
+ for k, v := range metadata {
+ delete(metadata, k)
+ metadata[encoder.EncodeToString([]byte(k))] = v
+ }
+ return metadata
+}
+
+// nolint
+func decodeConsulMetadata(metadata map[string]string) map[string]string {
+ if metadata == nil {
+ metadata = make(map[string]string, 1)
+ }
+ encoder := base64.RawStdEncoding
+ for k, v := range metadata {
+ delete(metadata, k)
Review comment:
using another map instead as the above suggestions.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] beiwei30 commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
beiwei30 commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r485309538
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,431 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd *consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ csd.ttl.Range(func(key, t interface{}) bool {
+ close(t.(chan struct{}))
+ csd.ttl.Delete(key)
+ return true
+ })
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ logger.Errorf("consul register the instance %s fail:%v", instance.GetServiceName(), err)
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ return csd.registerTtl(instance)
+}
+
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+ checkID := buildID(instance)
+
+ stopChan := make(chan struct{})
+ csd.ttl.LoadOrStore(buildID(instance), stopChan)
+
+ period := time.Duration(csd.checkPassInterval/8) * time.Millisecond
+ timer := time.NewTimer(period)
+ go func() {
+ for {
+ select {
+ case <-timer.C:
+ timer.Reset(period)
+ err := csd.consulClient.Agent().PassTTL(fmt.Sprintf("service:%s", checkID), "")
+ if err != nil {
+ logger.Warnf("pass ttl heartbeat fail:%v", err)
+ break
+ }
+ logger.Debugf("passed ttl heartbeat for %s", checkID)
+ break
+ case <-stopChan:
+ logger.Info("ttl %s for service %s is stopped", checkID, instance.GetServiceName())
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Update(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Warnf("unregister instance %s fail:%v", instance.GetServiceName(), err)
+ }
+ return csd.consulClient.Agent().ServiceRegister(ins)
+}
+
+func (csd *consulServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Errorf("unregister service instance %s,error: %v", instance.GetId(), err)
+ return err
+ }
+
+ stopChanel, ok := csd.ttl.Load(buildID(instance))
+ if !ok {
+ logger.Warnf("ttl for service instance %s didn't exist", instance.GetId())
+ return nil
+ }
+ close(stopChanel.(chan struct{}))
+ csd.ttl.Delete(buildID(instance))
+ return nil
+}
+
+func (csd *consulServiceDiscovery) GetDefaultPageSize() int {
+ return registry.DefaultPageSize
+}
+
+func (csd *consulServiceDiscovery) GetServices() *gxset.HashSet {
+
+ var res = gxset.NewSet()
+ services, _, err := csd.consulClient.Catalog().Services(nil)
+ if err != nil {
+ logger.Errorf("get services,error: %v", err)
+ return res
+ }
+
+ for service, _ := range services {
+ res.Add(service)
+ }
+ return res
+
+}
+
+// encodeConsulMetadata because consul validate key strictly.
+func encodeConsulMetadata(metadata map[string]string) map[string]string {
+ consulMetadata := make(map[string]string, 8)
+ if metadata == nil {
+ return consulMetadata
+ }
+ encoder := base64.RawStdEncoding
+ for k, v := range metadata {
+ consulMetadata[encoder.EncodeToString([]byte(k))] = v
+ }
+ return consulMetadata
+}
+
+// nolint
+func decodeConsulMetadata(metadata map[string]string) map[string]string {
+ dubboMetadata := make(map[string]string, 8)
+ if metadata == nil {
+ return dubboMetadata
+ }
+ encoder := base64.RawStdEncoding
+ for k, v := range metadata {
+ kBytes, err := encoder.DecodeString(k)
+ if err != nil {
+ logger.Warnf("can not decoded consul metadata key %s", k)
+ continue
+ }
+ dubboMetadata[string(kBytes)] = v
+ }
+ return dubboMetadata
+}
+
+func (csd *consulServiceDiscovery) GetInstances(serviceName string) []registry.ServiceInstance {
+ instances, _, err := csd.consulClient.Health().Service(serviceName, csd.tag, true, &consul.QueryOptions{
+ WaitTime: time.Duration(csd.checkPassInterval),
+ })
+ if err != nil {
+ logger.Errorf("get instances for service %s,error: %v", serviceName, err)
+ return nil
+ }
+
+ res := make([]registry.ServiceInstance, 0, len(instances))
+ for _, ins := range instances {
+ metadata := ins.Service.Meta
+
+ // enable status
+ enableStr := metadata[enable]
+ delete(metadata, enable)
+ enable, _ := strconv.ParseBool(enableStr)
+ metadata = decodeConsulMetadata(metadata)
+
+ // health status
+ status := ins.Checks.AggregatedStatus()
+ healthy := false
+ if status == consul.HealthPassing {
+ healthy = true
+ }
+ res = append(res, ®istry.DefaultServiceInstance{
+ Id: ins.Service.ID,
+ ServiceName: ins.Service.Service,
+ Host: ins.Service.Address,
+ Port: ins.Service.Port,
+ Enable: enable,
+ Healthy: healthy,
+ Metadata: metadata,
+ })
+ }
+
+ return res
+}
+
+func (csd *consulServiceDiscovery) GetInstancesByPage(serviceName string, offset int, pageSize int) gxpage.Pager {
+ all := csd.GetInstances(serviceName)
+ res := make([]interface{}, 0, pageSize)
+ for i := offset; i < len(all) && i < offset+pageSize; i++ {
+ res = append(res, all[i])
+ }
+ return gxpage.New(offset, pageSize, res, len(all))
+}
+
+func (csd *consulServiceDiscovery) GetHealthyInstancesByPage(serviceName string, offset int, pageSize int, healthy bool) gxpage.Pager {
+ all := csd.GetInstances(serviceName)
+ res := make([]interface{}, 0, pageSize)
+ // could not use res = all[a:b] here because the res should be []interface{}, not []ServiceInstance
+ var (
+ i = offset
+ count = 0
+ )
+ for i < len(all) && count < pageSize {
+ ins := all[i]
+ if ins.IsHealthy() == healthy {
+ res = append(res, all[i])
+ count++
+ }
+ i++
+ }
+ return gxpage.New(offset, pageSize, res, len(all))
+}
+
+func (csd *consulServiceDiscovery) GetRequestInstances(serviceNames []string, offset int, requestedSize int) map[string]gxpage.Pager {
+ res := make(map[string]gxpage.Pager, len(serviceNames))
+ for _, name := range serviceNames {
+ res[name] = csd.GetInstancesByPage(name, offset, requestedSize)
+ }
+ return res
+}
+
+func (csd *consulServiceDiscovery) AddListener(listener *registry.ServiceInstancesChangedListener) error {
+
+ params := make(map[string]interface{}, 8)
+ params["type"] = "service"
Review comment:
make this constants?
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] zhangshen023 commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
zhangshen023 commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r485591084
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,431 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd *consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ csd.ttl.Range(func(key, t interface{}) bool {
+ close(t.(chan struct{}))
+ csd.ttl.Delete(key)
+ return true
+ })
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ logger.Errorf("consul register the instance %s fail:%v", instance.GetServiceName(), err)
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ return csd.registerTtl(instance)
+}
+
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+ checkID := buildID(instance)
+
+ stopChan := make(chan struct{})
+ csd.ttl.LoadOrStore(buildID(instance), stopChan)
+
+ period := time.Duration(csd.checkPassInterval/8) * time.Millisecond
+ timer := time.NewTimer(period)
+ go func() {
+ for {
+ select {
+ case <-timer.C:
+ timer.Reset(period)
+ err := csd.consulClient.Agent().PassTTL(fmt.Sprintf("service:%s", checkID), "")
+ if err != nil {
+ logger.Warnf("pass ttl heartbeat fail:%v", err)
+ break
+ }
+ logger.Debugf("passed ttl heartbeat for %s", checkID)
+ break
+ case <-stopChan:
+ logger.Info("ttl %s for service %s is stopped", checkID, instance.GetServiceName())
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Update(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Warnf("unregister instance %s fail:%v", instance.GetServiceName(), err)
+ }
+ return csd.consulClient.Agent().ServiceRegister(ins)
+}
+
+func (csd *consulServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Errorf("unregister service instance %s,error: %v", instance.GetId(), err)
+ return err
+ }
+
+ stopChanel, ok := csd.ttl.Load(buildID(instance))
+ if !ok {
+ logger.Warnf("ttl for service instance %s didn't exist", instance.GetId())
+ return nil
+ }
+ close(stopChanel.(chan struct{}))
+ csd.ttl.Delete(buildID(instance))
+ return nil
+}
+
+func (csd *consulServiceDiscovery) GetDefaultPageSize() int {
+ return registry.DefaultPageSize
+}
+
+func (csd *consulServiceDiscovery) GetServices() *gxset.HashSet {
+
+ var res = gxset.NewSet()
+ services, _, err := csd.consulClient.Catalog().Services(nil)
+ if err != nil {
+ logger.Errorf("get services,error: %v", err)
+ return res
+ }
+
+ for service, _ := range services {
+ res.Add(service)
+ }
+ return res
+
+}
+
+// encodeConsulMetadata because consul validate key strictly.
+func encodeConsulMetadata(metadata map[string]string) map[string]string {
+ consulMetadata := make(map[string]string, 8)
+ if metadata == nil {
+ return consulMetadata
+ }
Review comment:
lgtm
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] beiwei30 commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
beiwei30 commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r484746651
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,422 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+)
+
+var (
+ initLock sync.Mutex
Review comment:
this var is un-used.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] AlexStocks merged pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
AlexStocks merged pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] AlexStocks commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
AlexStocks commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r487393253
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
+ if csd.consulClient == nil {
+ return nil, perrors.New("consul client is destroyed or not ready!")
+ }
+ return csd.consulClient, nil
+}
Review comment:
add a blank line btw two funcs.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] AlexStocks commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
AlexStocks commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r487393057
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
Review comment:
why u do not use lock inside this func?
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] fangyincheng commented on a change in pull request #701: consul service discovery
Posted by GitBox <gi...@apache.org>.
fangyincheng commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r467475789
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,437 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ "github.com/hashicorp/go-hclog"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+
+ instance, ok := instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ initLock.Lock()
+ defer initLock.Unlock()
+
+ // double check
+ instance, ok = instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ pageSize := 20
+ if remoteConfig.Params != nil {
+ if tmp, OK := remoteConfig.Params[PageSize]; OK {
+ intTmp, err := strconv.Atoi(tmp)
+ if err == nil && intTmp > 20 {
+ pageSize = intTmp
+ }
+ }
+ }
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ PageSize: pageSize,
+ ttl: make(map[string]chan struct{}),
+ }, nil
+}
+
+// nacosServiceDiscovery is the implementation of service discovery based on nacos.
+// There is a problem, the go client for nacos does not support the id field.
+// we will use the metadata to store the id of ServiceInstance
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ PageSize int
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl map[string]chan struct{}
+}
+
+func (csd *consulServiceDiscovery) Initialize(registryURL common.URL) error {
+ csd.serviceUrl = registryURL
+ csd.checkPassInterval = registryURL.GetParamInt(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL)
+ csd.tag = registryURL.GetParam(QUERY_TAG, "")
+ csd.tags = strings.Split(registryURL.GetParam("tags", ""), ",")
+ aclToken := registryURL.GetParam(ACL_TOKEN, "")
+ config := &consul.Config{Address: csd.address, Token: aclToken}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return perrors.WithMessage(err, "create consul client failed.")
+ }
+ csd.consulClient = client
+ return nil
+}
+func (csd consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ for _, t := range csd.ttl {
+ close(t)
+ }
+ csd.ttl = nil
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ csd.registerTtl(instance)
+
+ return nil
+
+}
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+
+ checkID := buildID(instance)
+
+ stopChan := make(chan struct{})
+ csd.ttl[buildID(instance)] = stopChan
+
+ period := time.Duration(csd.checkPassInterval/8) * time.Millisecond
+ timer := time.NewTimer(period)
+ go func() {
+ for {
+ select {
+ case <-timer.C:
+ timer.Reset(period)
+ err := csd.consulClient.Agent().PassTTL(checkID, "")
+ if err != nil {
+ logger.Warnf("pass ttl heartbeat fail:%v", err)
+ break
+ }
+ logger.Debugf("passed ttl heartbeat for %s", checkID)
+ break
+ case <-stopChan:
+ logger.Info("ttl %s for service %s is stopped", checkID, instance.GetServiceName())
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (csd consulServiceDiscovery) Update(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Warnf("unregister instance %s fail:%v", instance.GetServiceName(), err)
+ }
+ err = csd.consulClient.Agent().ServiceRegister(ins)
+ return err
+}
+
+func (csd consulServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ return err
+ }
+ stopChanel, ok := csd.ttl[buildID(instance)]
+ if ok {
+ close(stopChanel)
+ delete(csd.ttl, buildID(instance))
+ }
+ return nil
+}
+
+func (csd consulServiceDiscovery) GetDefaultPageSize() int {
+ return csd.PageSize
+}
+
+func (csd consulServiceDiscovery) GetServices() *gxset.HashSet {
+
+ var res = gxset.NewSet()
+ services, _, err := csd.consulClient.Catalog().Services(nil)
+ if err != nil {
+ return res
+ }
+
+ for service, _ := range services {
+ res.Add(service)
+ }
+ return res
+
+}
+
+func (csd consulServiceDiscovery) GetInstances(serviceName string) []registry.ServiceInstance {
+ waitTime := csd.serviceUrl.GetParamInt(WATCH_TIMEOUT, DEFAULT_WATCH_TIMEOUT) / 1000
+ instances, _, err := csd.consulClient.Health().Service(serviceName, csd.tag, true, &consul.QueryOptions{
+ WaitTime: time.Duration(waitTime),
+ })
+ if err != nil {
+ return nil
Review comment:
add log for err
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] gaoxinge commented on a change in pull request #701: consul service discovery
Posted by GitBox <gi...@apache.org>.
gaoxinge commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r467985392
##########
File path: registry/consul/service_discovery_test.go
##########
@@ -0,0 +1,239 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "math/rand"
+ "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/common/extension"
+ "github.com/apache/dubbo-go/common/observer"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+ "github.com/apache/dubbo-go/remoting/consul"
+)
+
+var (
+ testName = "test"
+ consulCheckPassInterval = 17000
+ consulDeregisterCriticalServiceAfter = "20s"
+ consulWatchTimeout = 60000
+ registryURL = common.URL{
+ Path: "",
+ Username: "",
+ Password: "",
+ Methods: nil,
+ SubURL: nil,
+ }
+)
+
+func TestConsulServiceDiscovery_newConsulServiceDiscovery(t *testing.T) {
+ name := "consul1"
+ _, err := newConsulServiceDiscovery(name)
+ assert.NotNil(t, err)
+
+ sdc := &config.ServiceDiscoveryConfig{
+ Protocol: "consul",
+ RemoteRef: "mock",
+ }
+
+ config.GetBaseConfig().ServiceDiscoveries[name] = sdc
+
+ _, err = newConsulServiceDiscovery(name)
+ assert.NotNil(t, err)
+
+ config.GetBaseConfig().Remotes["mock"] = &config.RemoteConfig{
+ Address: "localhost:8081",
+ }
+
+ res, err := newConsulServiceDiscovery(name)
+ assert.Nil(t, err)
+ assert.NotNil(t, res)
+}
+
+func TestConsulServiceDiscovery_Destroy(t *testing.T) {
+ prepareData()
+ serviceDiscovery, err := extension.GetServiceDiscovery(constant.CONSUL_KEY, testName)
+ _, registryUrl := prepareService()
+ serviceDiscovery.Initialize(registryUrl)
+ assert.Nil(t, err)
+ assert.NotNil(t, serviceDiscovery)
+ err = serviceDiscovery.Destroy()
+ assert.Nil(t, err)
+ assert.Nil(t, serviceDiscovery.(*consulServiceDiscovery).consulClient)
+}
+
+func TestConsulServiceDiscovery_CRUD(t *testing.T) {
+ // start consul agent
+ consulAgent := consul.NewConsulAgent(t, registryPort)
+ defer consulAgent.Shutdown()
+
+ prepareData()
+ var eventDispatcher = MockEventDispatcher{Notify: make(chan struct{}, 1)}
+ extension.SetEventDispatcher("mock", func() observer.EventDispatcher {
+ return &eventDispatcher
+ })
+
+ extension.SetAndInitGlobalDispatcher("mock")
+ rand.Seed(time.Now().Unix())
+
+ instance, registryUrl := prepareService()
+
+ // clean data
+ serviceDiscovery, err := extension.GetServiceDiscovery(constant.CONSUL_KEY, testName)
+ assert.Nil(t, err)
+
+ err = serviceDiscovery.Initialize(registryUrl)
+ assert.Nil(t, err)
+
+ err = serviceDiscovery.Unregister(instance)
+ assert.Nil(t, err)
+
+ err = serviceDiscovery.Register(instance)
+ assert.Nil(t, err)
+
+ //sometimes nacos may be failed to push update of instance,
+ //so it need 10s to pull, we sleep 10 second to make sure instance has been update
+ time.Sleep(3 * time.Second)
+ page := serviceDiscovery.GetHealthyInstancesByPage(instance.GetServiceName(), 0, 10, true)
+ assert.NotNil(t, page)
+ assert.Equal(t, 0, page.GetOffset())
+ assert.Equal(t, 10, page.GetPageSize())
+ assert.Equal(t, 1, page.GetDataSize())
+
+ instanceResult := page.GetData()[0].(*registry.DefaultServiceInstance)
+ assert.NotNil(t, instanceResult)
+ assert.Equal(t, buildID(instance), instanceResult.GetId())
+ assert.Equal(t, instance.GetHost(), instanceResult.GetHost())
+ assert.Equal(t, instance.GetPort(), instanceResult.GetPort())
+ assert.Equal(t, instance.GetServiceName(), instanceResult.GetServiceName())
+ assert.Equal(t, 0, len(instanceResult.GetMetadata()))
+
+ instance.GetMetadata()["aaa"] = "bbb"
+ err = serviceDiscovery.Update(instance)
+ assert.Nil(t, err)
+
+ time.Sleep(3 * time.Second)
+ pageMap := serviceDiscovery.GetRequestInstances([]string{instance.GetServiceName()}, 0, 1)
+ assert.Equal(t, 1, len(pageMap))
+
+ page = pageMap[instance.GetServiceName()]
+ assert.NotNil(t, page)
+ assert.Equal(t, 1, len(page.GetData()))
+
+ instanceResult = page.GetData()[0].(*registry.DefaultServiceInstance)
+ v, _ := instanceResult.GetMetadata()["aaa"]
+ assert.Equal(t, "bbb", v)
+
+ // test dispatcher event
+ //err = serviceDiscovery.DispatchEventByServiceName(instanceResult.GetServiceName())
+ //assert.Nil(t, err)
+
+ // test AddListener
+ err = serviceDiscovery.AddListener(®istry.ServiceInstancesChangedListener{ServiceName: instance.GetServiceName()})
+ assert.Nil(t, err)
+ err = serviceDiscovery.Unregister(instance)
+ assert.Nil(t, err)
+ timer := time.NewTimer(time.Second * 10)
+ select {
+ case <-eventDispatcher.Notify:
+ assert.NotNil(t, eventDispatcher.Event)
+ break
+ case <-timer.C:
+ assert.Fail(t, "")
+ break
+ }
+}
+
+func prepareData() {
+ config.GetBaseConfig().ServiceDiscoveries[testName] = &config.ServiceDiscoveryConfig{
+ Protocol: "consul",
+ RemoteRef: testName,
+ }
+
+ config.GetBaseConfig().Remotes[testName] = &config.RemoteConfig{
+ Address: fmt.Sprintf("%s:%d", registryHost, registryPort),
+ }
+}
+func prepareService() (registry.ServiceInstance, common.URL) {
+ id := "id"
+
+ registryUrl, _ := common.NewURL(protocol + "://" + providerHost + ":" + strconv.Itoa(providerPort) + "/" + service + "?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&consul-check-pass-interval=" + strconv.Itoa(consulCheckPassInterval) + "&consul-deregister-critical-service-after=" + consulDeregisterCriticalServiceAfter + "&" +
+ "consul-watch-timeout=" + strconv.Itoa(consulWatchTimeout))
+
+ return ®istry.DefaultServiceInstance{
+ Id: id,
+ ServiceName: service,
+ Host: registryHost,
+ Port: registryPort,
+ Enable: true,
+ Healthy: true,
+ Metadata: nil,
+ }, registryUrl
+}
+
+type MockEventDispatcher struct {
+ Notify chan struct{}
+ Event observer.Event
+}
+
+// AddEventListener do nothing
+func (m MockEventDispatcher) AddEventListener(listener observer.EventListener) {
Review comment:
- use pointer type `*MockEventDispatcher`
- modify all methods below to use pointer receiver `m *MockEventDispatcher`
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] AlexStocks commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
AlexStocks commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r487392967
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
Review comment:
move it above the consulClient
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] gaoxinge commented on a change in pull request #701: consul service discovery
Posted by GitBox <gi...@apache.org>.
gaoxinge commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r467389250
##########
File path: registry/event/event_publishing_service_discovery.go
##########
@@ -18,6 +18,10 @@
package event
import (
+ "sync"
+)
+import (
+ "github.com/apache/dubbo-go/common"
Review comment:
move it to third import block
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,439 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ "github.com/hashicorp/go-hclog"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+
+ instance, ok := instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ initLock.Lock()
+ defer initLock.Unlock()
+
+ // double check
+ instance, ok = instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ pageSize := 20
+ if remoteConfig.Params != nil {
+ if tmp, OK := remoteConfig.Params[PageSize]; OK {
+ intTmp, err := strconv.Atoi(tmp)
+ if err == nil && intTmp > 20 {
+ pageSize = intTmp
+ }
+ }
+ }
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ PageSize: pageSize,
+ ttl: make(map[string]chan struct{}),
+ }, nil
+}
+
+// nacosServiceDiscovery is the implementation of service discovery based on nacos.
+// There is a problem, the go client for nacos does not support the id field.
+// we will use the metadata to store the id of ServiceInstance
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ PageSize int
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl map[string]chan struct{}
+}
+
+func (csd *consulServiceDiscovery) Initialize(registryURL common.URL) error {
+ csd.serviceUrl = registryURL
+ csd.checkPassInterval = registryURL.GetParamInt(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL)
+ csd.tag = registryURL.GetParam(QUERY_TAG, "")
+ csd.tags = strings.Split(registryURL.GetParam("tags", ""), ",")
+ aclToken := registryURL.GetParam(ACL_TOKEN, "")
+ config := &consul.Config{Address: csd.address, Token: aclToken}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return perrors.WithMessage(err, "create consul client failed.")
+ }
+ csd.consulClient = client
+ return nil
+}
+func (csd consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ for _, t := range csd.ttl {
+ close(t)
+ }
+ csd.ttl = nil
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ csd.registerTtl(instance)
+
+ return nil
+
+}
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+
+ checkID := buildID(instance)
+
+ stopChan := make(chan struct{})
+ csd.ttl[buildID(instance)] = stopChan
+
+ period := time.Duration(csd.checkPassInterval/8) * time.Millisecond
+ timer := time.NewTimer(period)
+ go func() {
+ for {
+ select {
+ case <-timer.C:
+ timer.Reset(period)
+ err := csd.consulClient.Agent().PassTTL(checkID, "")
+ if err != nil {
+ logger.Warnf("pass ttl heartbeat fail:%v", err)
+ break
+ }
+ logger.Debugf("passed ttl heartbeat for %s", checkID)
+ break
+ case <-stopChan:
+ logger.Info("ttl %s for service %s is stopped", checkID, instance.GetServiceName())
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (csd consulServiceDiscovery) Update(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Warnf("unregister instance %s fail:%v", instance.GetServiceName(), err)
+ }
+ err = csd.consulClient.Agent().ServiceRegister(ins)
+ return err
+}
+
+func (csd consulServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ return err
+ }
+ stopChanel, ok := csd.ttl[buildID(instance)]
+ if ok {
+ close(stopChanel)
+ delete(csd.ttl, buildID(instance))
+ }
+ return nil
+}
+
+func (csd consulServiceDiscovery) GetDefaultPageSize() int {
+ return csd.PageSize
+}
+
+func (csd consulServiceDiscovery) GetServices() *gxset.HashSet {
+
+ var res = gxset.NewSet()
+ services, _, err := csd.consulClient.Catalog().Services(nil)
+ if err != nil {
+ return res
+ }
+
+ for service, _ := range services {
+ res.Add(service)
+ }
+ return res
+
+}
+
+func (csd consulServiceDiscovery) GetInstances(serviceName string) []registry.ServiceInstance {
+ waitTime := csd.serviceUrl.GetParamInt(WATCH_TIMEOUT, DEFAULT_WATCH_TIMEOUT) / 1000
+ instances, _, err := csd.consulClient.Health().Service(serviceName, csd.tag, true, &consul.QueryOptions{
+ WaitTime: time.Duration(waitTime),
+ })
+ if err != nil {
+ return nil
+ }
+
+ res := make([]registry.ServiceInstance, 0, len(instances))
+ for _, ins := range instances {
+ metadata := ins.Service.Meta
+
+ // enable status
+ enableStr := metadata[Enable]
+ delete(metadata, Enable)
+ enable, _ := strconv.ParseBool(enableStr)
+
+ // health status
+ status := ins.Checks.AggregatedStatus()
+ healthy := false
+ if status == consul.HealthPassing {
+ healthy = true
+ }
+ res = append(res, ®istry.DefaultServiceInstance{
+ Id: ins.Service.ID,
+ ServiceName: ins.Service.Service,
+ Host: ins.Service.Address,
+ Port: ins.Service.Port,
+ Enable: enable,
+ Healthy: healthy,
+ Metadata: metadata,
+ })
+ }
+
+ return res
+}
+
+func (csd consulServiceDiscovery) GetInstancesByPage(serviceName string, offset int, pageSize int) gxpage.Pager {
+ all := csd.GetInstances(serviceName)
+ res := make([]interface{}, 0, pageSize)
+ for i := offset; i < len(all) && i < offset+pageSize; i++ {
+ res = append(res, all[i])
+ }
+ return gxpage.New(offset, pageSize, res, len(all))
+}
+
+func (csd consulServiceDiscovery) GetHealthyInstancesByPage(serviceName string, offset int, pageSize int, healthy bool) gxpage.Pager {
+ all := csd.GetInstances(serviceName)
+ res := make([]interface{}, 0, pageSize)
+ // could not use res = all[a:b] here because the res should be []interface{}, not []ServiceInstance
+ var (
+ i = offset
+ count = 0
+ )
+ for i < len(all) && count < pageSize {
+ ins := all[i]
+ if ins.IsHealthy() == healthy {
+ res = append(res, all[i])
+ count++
+ }
+ i++
+ }
+ return gxpage.New(offset, pageSize, res, len(all))
+}
+
+func (csd consulServiceDiscovery) GetRequestInstances(serviceNames []string, offset int, requestedSize int) map[string]gxpage.Pager {
+ res := make(map[string]gxpage.Pager, len(serviceNames))
+ for _, name := range serviceNames {
+ res[name] = csd.GetInstancesByPage(name, offset, requestedSize)
+ }
+ return res
+}
+
+func (csd consulServiceDiscovery) AddListener(listener *registry.ServiceInstancesChangedListener) error {
+
+ params := make(map[string]interface{}, 8)
+ params["type"] = "service"
+ params["service"] = listener.ServiceName
+ params["passingonly"] = true
+ //params["tag"] = "dubbo"
+ //params["passingonly"] = true
Review comment:
remove comment
##########
File path: registry/event/event_publishing_service_deiscovery_test.go
##########
@@ -18,6 +18,7 @@
package event
import (
+ "github.com/apache/dubbo-go/common"
Review comment:
move it to third import block
##########
File path: registry/event/event_publishing_service_discovery.go
##########
@@ -18,6 +18,10 @@
package event
import (
+ "sync"
+)
+import (
Review comment:
add a blank line before import
##########
File path: registry/service_discovery.go
##########
@@ -22,6 +22,7 @@ import (
)
import (
+ "github.com/apache/dubbo-go/common"
Review comment:
move it to third import block
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] codecov-commenter edited a comment on pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
codecov-commenter edited a comment on pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#issuecomment-673190849
# [Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=h1) Report
> Merging [#701](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=desc) into [develop](https://codecov.io/gh/apache/dubbo-go/commit/6388c4ab41d1748522a3e7ce8f8fd4dd87b194dd?el=desc) will **increase** coverage by `0.22%`.
> The diff coverage is `74.71%`.
[](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=tree)
```diff
@@ Coverage Diff @@
## develop #701 +/- ##
===========================================
+ Coverage 63.69% 63.91% +0.22%
===========================================
Files 240 241 +1
Lines 12977 13245 +268
===========================================
+ Hits 8266 8466 +200
- Misses 3912 3964 +52
- Partials 799 815 +16
```
| [Impacted Files](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [registry/etcdv3/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvZXRjZHYzL3NlcnZpY2VfZGlzY292ZXJ5Lmdv) | `16.29% <0.00%> (-0.25%)` | :arrow_down: |
| [...gistry/event/event\_publishing\_service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvZXZlbnQvZXZlbnRfcHVibGlzaGluZ19zZXJ2aWNlX2Rpc2NvdmVyeS5nbw==) | `38.09% <0.00%> (-4.02%)` | :arrow_down: |
| [registry/nacos/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvbmFjb3Mvc2VydmljZV9kaXNjb3ZlcnkuZ28=) | `66.27% <0.00%> (-0.78%)` | :arrow_down: |
| [registry/zookeeper/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvem9va2VlcGVyL3NlcnZpY2VfZGlzY292ZXJ5Lmdv) | `82.35% <0.00%> (-0.99%)` | :arrow_down: |
| [registry/consul/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvY29uc3VsL3NlcnZpY2VfZGlzY292ZXJ5Lmdv) | `77.95% <77.95%> (ø)` | |
| [registry/etcdv3/registry.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvZXRjZHYzL3JlZ2lzdHJ5Lmdv) | `69.01% <100.00%> (ø)` | |
| [...try/servicediscovery/service\_discovery\_registry.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvc2VydmljZWRpc2NvdmVyeS9zZXJ2aWNlX2Rpc2NvdmVyeV9yZWdpc3RyeS5nbw==) | `12.37% <100.00%> (+0.45%)` | :arrow_up: |
| [config/reference\_config.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-Y29uZmlnL3JlZmVyZW5jZV9jb25maWcuZ28=) | `79.82% <0.00%> (-0.71%)` | :arrow_down: |
| [protocol/jsonrpc/server.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cHJvdG9jb2wvanNvbnJwYy9zZXJ2ZXIuZ28=) | `61.05% <0.00%> (-0.30%)` | :arrow_down: |
| [config/config\_loader.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-Y29uZmlnL2NvbmZpZ19sb2FkZXIuZ28=) | `57.27% <0.00%> (-0.07%)` | :arrow_down: |
| ... and [8 more](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree-more) | |
------
[Continue to review full report at Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=footer). Last update [6388c4a...262bf06](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] codecov-commenter edited a comment on pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
codecov-commenter edited a comment on pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#issuecomment-673190849
# [Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=h1) Report
> Merging [#701](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=desc) into [develop](https://codecov.io/gh/apache/dubbo-go/commit/d542f6209b7ccd263d795138c1b33753284e3890?el=desc) will **increase** coverage by `0.22%`.
> The diff coverage is `74.71%`.
[](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=tree)
```diff
@@ Coverage Diff @@
## develop #701 +/- ##
===========================================
+ Coverage 63.69% 63.91% +0.22%
===========================================
Files 240 241 +1
Lines 12986 13245 +259
===========================================
+ Hits 8271 8466 +195
- Misses 3912 3964 +52
- Partials 803 815 +12
```
| [Impacted Files](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [registry/etcdv3/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvZXRjZHYzL3NlcnZpY2VfZGlzY292ZXJ5Lmdv) | `16.29% <0.00%> (-0.25%)` | :arrow_down: |
| [...gistry/event/event\_publishing\_service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvZXZlbnQvZXZlbnRfcHVibGlzaGluZ19zZXJ2aWNlX2Rpc2NvdmVyeS5nbw==) | `38.09% <0.00%> (-4.02%)` | :arrow_down: |
| [registry/nacos/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvbmFjb3Mvc2VydmljZV9kaXNjb3ZlcnkuZ28=) | `66.27% <0.00%> (-0.78%)` | :arrow_down: |
| [registry/zookeeper/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvem9va2VlcGVyL3NlcnZpY2VfZGlzY292ZXJ5Lmdv) | `82.35% <0.00%> (-0.99%)` | :arrow_down: |
| [registry/consul/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvY29uc3VsL3NlcnZpY2VfZGlzY292ZXJ5Lmdv) | `77.95% <77.95%> (ø)` | |
| [registry/etcdv3/registry.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvZXRjZHYzL3JlZ2lzdHJ5Lmdv) | `69.01% <100.00%> (ø)` | |
| [...try/servicediscovery/service\_discovery\_registry.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvc2VydmljZWRpc2NvdmVyeS9zZXJ2aWNlX2Rpc2NvdmVyeV9yZWdpc3RyeS5nbw==) | `12.37% <100.00%> (+0.45%)` | :arrow_up: |
| [metadata/report/delegate/delegate\_report.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-bWV0YWRhdGEvcmVwb3J0L2RlbGVnYXRlL2RlbGVnYXRlX3JlcG9ydC5nbw==) | `29.41% <0.00%> (-8.83%)` | :arrow_down: |
| [remoting/kubernetes/listener.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVtb3Rpbmcva3ViZXJuZXRlcy9saXN0ZW5lci5nbw==) | `52.83% <0.00%> (ø)` | |
| [filter/filter\_impl/hystrix\_filter.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-ZmlsdGVyL2ZpbHRlcl9pbXBsL2h5c3RyaXhfZmlsdGVyLmdv) | `68.64% <0.00%> (ø)` | |
| ... and [4 more](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree-more) | |
------
[Continue to review full report at Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=footer). Last update [d542f62...9a644a6](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] codecov-commenter edited a comment on pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
codecov-commenter edited a comment on pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#issuecomment-673190849
# [Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=h1) Report
> Merging [#701](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=desc) into [develop](https://codecov.io/gh/apache/dubbo-go/commit/bb197cc70d7810a017ac1c0e5addbf992e69a49b?el=desc) will **decrease** coverage by `0.08%`.
> The diff coverage is `76.19%`.
[](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=tree)
```diff
@@ Coverage Diff @@
## develop #701 +/- ##
===========================================
- Coverage 63.70% 63.61% -0.09%
===========================================
Files 240 245 +5
Lines 12977 13784 +807
===========================================
+ Hits 8267 8769 +502
- Misses 3911 4135 +224
- Partials 799 880 +81
```
| [Impacted Files](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [registry/zookeeper/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvem9va2VlcGVyL3NlcnZpY2VfZGlzY292ZXJ5Lmdv) | `82.35% <0.00%> (-0.99%)` | :arrow_down: |
| [registry/consul/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvY29uc3VsL3NlcnZpY2VfZGlzY292ZXJ5Lmdv) | `76.61% <76.61%> (ø)` | |
| [...try/servicediscovery/service\_discovery\_registry.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvc2VydmljZWRpc2NvdmVyeS9zZXJ2aWNlX2Rpc2NvdmVyeV9yZWdpc3RyeS5nbw==) | `12.14% <100.00%> (+0.22%)` | :arrow_up: |
| [filter/filter\_impl/metrics\_filter.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-ZmlsdGVyL2ZpbHRlcl9pbXBsL21ldHJpY3NfZmlsdGVyLmdv) | `86.36% <0.00%> (-13.64%)` | :arrow_down: |
| [registry/kubernetes/registry.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkva3ViZXJuZXRlcy9yZWdpc3RyeS5nbw==) | `55.55% <0.00%> (-9.26%)` | :arrow_down: |
| [filter/filter\_impl/access\_log\_filter.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-ZmlsdGVyL2ZpbHRlcl9pbXBsL2FjY2Vzc19sb2dfZmlsdGVyLmdv) | `64.03% <0.00%> (-7.00%)` | :arrow_down: |
| [cluster/router/tag/tag\_router.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-Y2x1c3Rlci9yb3V0ZXIvdGFnL3RhZ19yb3V0ZXIuZ28=) | `75.15% <0.00%> (-0.31%)` | :arrow_down: |
| [protocol/dubbo/dubbo\_invoker.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cHJvdG9jb2wvZHViYm8vZHViYm9faW52b2tlci5nbw==) | `81.96% <0.00%> (-0.30%)` | :arrow_down: |
| [protocol/dubbo/listener.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cHJvdG9jb2wvZHViYm8vbGlzdGVuZXIuZ28=) | `57.29% <0.00%> (-0.23%)` | :arrow_down: |
| [protocol/result.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cHJvdG9jb2wvcmVzdWx0Lmdv) | `0.00% <0.00%> (ø)` | |
| ... and [8 more](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree-more) | |
------
[Continue to review full report at Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=footer). Last update [bb197cc...b3aab08](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] gaoxinge commented on a change in pull request #701: consul service discovery
Posted by GitBox <gi...@apache.org>.
gaoxinge commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r467983903
##########
File path: registry/consul/service_discovery_test.go
##########
@@ -0,0 +1,239 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "math/rand"
+ "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/common/extension"
+ "github.com/apache/dubbo-go/common/observer"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+ "github.com/apache/dubbo-go/remoting/consul"
+)
+
+var (
+ testName = "test"
+ consulCheckPassInterval = 17000
+ consulDeregisterCriticalServiceAfter = "20s"
+ consulWatchTimeout = 60000
+ registryURL = common.URL{
+ Path: "",
+ Username: "",
+ Password: "",
+ Methods: nil,
+ SubURL: nil,
+ }
+)
+
+func TestConsulServiceDiscovery_newConsulServiceDiscovery(t *testing.T) {
+ name := "consul1"
+ _, err := newConsulServiceDiscovery(name)
+ assert.NotNil(t, err)
+
+ sdc := &config.ServiceDiscoveryConfig{
+ Protocol: "consul",
+ RemoteRef: "mock",
+ }
+
+ config.GetBaseConfig().ServiceDiscoveries[name] = sdc
+
+ _, err = newConsulServiceDiscovery(name)
+ assert.NotNil(t, err)
+
+ config.GetBaseConfig().Remotes["mock"] = &config.RemoteConfig{
+ Address: "localhost:8081",
+ }
+
+ res, err := newConsulServiceDiscovery(name)
+ assert.Nil(t, err)
+ assert.NotNil(t, res)
+}
+
+func TestConsulServiceDiscovery_Destroy(t *testing.T) {
+ prepareData()
+ serviceDiscovery, err := extension.GetServiceDiscovery(constant.CONSUL_KEY, testName)
+ _, registryUrl := prepareService()
+ serviceDiscovery.Initialize(registryUrl)
+ assert.Nil(t, err)
+ assert.NotNil(t, serviceDiscovery)
+ err = serviceDiscovery.Destroy()
+ assert.Nil(t, err)
+ assert.Nil(t, serviceDiscovery.(*consulServiceDiscovery).consulClient)
+}
+
+func TestConsulServiceDiscovery_CRUD(t *testing.T) {
+ // start consul agent
+ consulAgent := consul.NewConsulAgent(t, registryPort)
+ defer consulAgent.Shutdown()
+
+ prepareData()
+ var eventDispatcher = MockEventDispatcher{Notify: make(chan struct{}, 1)}
+ extension.SetEventDispatcher("mock", func() observer.EventDispatcher {
+ return &eventDispatcher
+ })
+
+ extension.SetAndInitGlobalDispatcher("mock")
+ rand.Seed(time.Now().Unix())
+
+ instance, registryUrl := prepareService()
+
+ // clean data
+ serviceDiscovery, err := extension.GetServiceDiscovery(constant.CONSUL_KEY, testName)
+ assert.Nil(t, err)
+
+ err = serviceDiscovery.Initialize(registryUrl)
+ assert.Nil(t, err)
+
+ err = serviceDiscovery.Unregister(instance)
+ assert.Nil(t, err)
+
+ err = serviceDiscovery.Register(instance)
+ assert.Nil(t, err)
+
+ //sometimes nacos may be failed to push update of instance,
+ //so it need 10s to pull, we sleep 10 second to make sure instance has been update
+ time.Sleep(3 * time.Second)
+ page := serviceDiscovery.GetHealthyInstancesByPage(instance.GetServiceName(), 0, 10, true)
+ assert.NotNil(t, page)
+ assert.Equal(t, 0, page.GetOffset())
+ assert.Equal(t, 10, page.GetPageSize())
+ assert.Equal(t, 1, page.GetDataSize())
+
+ instanceResult := page.GetData()[0].(*registry.DefaultServiceInstance)
+ assert.NotNil(t, instanceResult)
+ assert.Equal(t, buildID(instance), instanceResult.GetId())
+ assert.Equal(t, instance.GetHost(), instanceResult.GetHost())
+ assert.Equal(t, instance.GetPort(), instanceResult.GetPort())
+ assert.Equal(t, instance.GetServiceName(), instanceResult.GetServiceName())
+ assert.Equal(t, 0, len(instanceResult.GetMetadata()))
+
+ instance.GetMetadata()["aaa"] = "bbb"
+ err = serviceDiscovery.Update(instance)
+ assert.Nil(t, err)
+
+ time.Sleep(3 * time.Second)
+ pageMap := serviceDiscovery.GetRequestInstances([]string{instance.GetServiceName()}, 0, 1)
+ assert.Equal(t, 1, len(pageMap))
+
+ page = pageMap[instance.GetServiceName()]
+ assert.NotNil(t, page)
+ assert.Equal(t, 1, len(page.GetData()))
+
+ instanceResult = page.GetData()[0].(*registry.DefaultServiceInstance)
+ v, _ := instanceResult.GetMetadata()["aaa"]
+ assert.Equal(t, "bbb", v)
+
+ // test dispatcher event
+ //err = serviceDiscovery.DispatchEventByServiceName(instanceResult.GetServiceName())
+ //assert.Nil(t, err)
+
+ // test AddListener
+ err = serviceDiscovery.AddListener(®istry.ServiceInstancesChangedListener{ServiceName: instance.GetServiceName()})
+ assert.Nil(t, err)
+ err = serviceDiscovery.Unregister(instance)
+ assert.Nil(t, err)
+ timer := time.NewTimer(time.Second * 10)
+ select {
+ case <-eventDispatcher.Notify:
+ assert.NotNil(t, eventDispatcher.Event)
+ break
+ case <-timer.C:
+ assert.Fail(t, "")
+ break
+ }
+}
+
+func prepareData() {
+ config.GetBaseConfig().ServiceDiscoveries[testName] = &config.ServiceDiscoveryConfig{
+ Protocol: "consul",
+ RemoteRef: testName,
+ }
+
+ config.GetBaseConfig().Remotes[testName] = &config.RemoteConfig{
+ Address: fmt.Sprintf("%s:%d", registryHost, registryPort),
+ }
+}
+func prepareService() (registry.ServiceInstance, common.URL) {
Review comment:
Add a blank line before `prepareService.`
##########
File path: registry/consul/service_discovery_test.go
##########
@@ -0,0 +1,239 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "math/rand"
+ "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/common/extension"
+ "github.com/apache/dubbo-go/common/observer"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+ "github.com/apache/dubbo-go/remoting/consul"
+)
+
+var (
+ testName = "test"
+ consulCheckPassInterval = 17000
+ consulDeregisterCriticalServiceAfter = "20s"
+ consulWatchTimeout = 60000
+ registryURL = common.URL{
+ Path: "",
+ Username: "",
+ Password: "",
+ Methods: nil,
+ SubURL: nil,
+ }
+)
+
+func TestConsulServiceDiscovery_newConsulServiceDiscovery(t *testing.T) {
+ name := "consul1"
+ _, err := newConsulServiceDiscovery(name)
+ assert.NotNil(t, err)
+
+ sdc := &config.ServiceDiscoveryConfig{
+ Protocol: "consul",
+ RemoteRef: "mock",
+ }
+
+ config.GetBaseConfig().ServiceDiscoveries[name] = sdc
+
+ _, err = newConsulServiceDiscovery(name)
+ assert.NotNil(t, err)
+
+ config.GetBaseConfig().Remotes["mock"] = &config.RemoteConfig{
+ Address: "localhost:8081",
+ }
+
+ res, err := newConsulServiceDiscovery(name)
+ assert.Nil(t, err)
+ assert.NotNil(t, res)
+}
+
+func TestConsulServiceDiscovery_Destroy(t *testing.T) {
+ prepareData()
+ serviceDiscovery, err := extension.GetServiceDiscovery(constant.CONSUL_KEY, testName)
+ _, registryUrl := prepareService()
+ serviceDiscovery.Initialize(registryUrl)
+ assert.Nil(t, err)
+ assert.NotNil(t, serviceDiscovery)
+ err = serviceDiscovery.Destroy()
+ assert.Nil(t, err)
+ assert.Nil(t, serviceDiscovery.(*consulServiceDiscovery).consulClient)
+}
+
+func TestConsulServiceDiscovery_CRUD(t *testing.T) {
+ // start consul agent
+ consulAgent := consul.NewConsulAgent(t, registryPort)
+ defer consulAgent.Shutdown()
+
+ prepareData()
+ var eventDispatcher = MockEventDispatcher{Notify: make(chan struct{}, 1)}
+ extension.SetEventDispatcher("mock", func() observer.EventDispatcher {
+ return &eventDispatcher
+ })
+
+ extension.SetAndInitGlobalDispatcher("mock")
+ rand.Seed(time.Now().Unix())
+
+ instance, registryUrl := prepareService()
+
+ // clean data
+ serviceDiscovery, err := extension.GetServiceDiscovery(constant.CONSUL_KEY, testName)
+ assert.Nil(t, err)
+
+ err = serviceDiscovery.Initialize(registryUrl)
+ assert.Nil(t, err)
+
+ err = serviceDiscovery.Unregister(instance)
+ assert.Nil(t, err)
+
+ err = serviceDiscovery.Register(instance)
+ assert.Nil(t, err)
+
+ //sometimes nacos may be failed to push update of instance,
+ //so it need 10s to pull, we sleep 10 second to make sure instance has been update
+ time.Sleep(3 * time.Second)
+ page := serviceDiscovery.GetHealthyInstancesByPage(instance.GetServiceName(), 0, 10, true)
+ assert.NotNil(t, page)
+ assert.Equal(t, 0, page.GetOffset())
+ assert.Equal(t, 10, page.GetPageSize())
+ assert.Equal(t, 1, page.GetDataSize())
+
+ instanceResult := page.GetData()[0].(*registry.DefaultServiceInstance)
+ assert.NotNil(t, instanceResult)
+ assert.Equal(t, buildID(instance), instanceResult.GetId())
+ assert.Equal(t, instance.GetHost(), instanceResult.GetHost())
+ assert.Equal(t, instance.GetPort(), instanceResult.GetPort())
+ assert.Equal(t, instance.GetServiceName(), instanceResult.GetServiceName())
+ assert.Equal(t, 0, len(instanceResult.GetMetadata()))
+
+ instance.GetMetadata()["aaa"] = "bbb"
+ err = serviceDiscovery.Update(instance)
+ assert.Nil(t, err)
+
+ time.Sleep(3 * time.Second)
+ pageMap := serviceDiscovery.GetRequestInstances([]string{instance.GetServiceName()}, 0, 1)
+ assert.Equal(t, 1, len(pageMap))
+
+ page = pageMap[instance.GetServiceName()]
+ assert.NotNil(t, page)
+ assert.Equal(t, 1, len(page.GetData()))
+
+ instanceResult = page.GetData()[0].(*registry.DefaultServiceInstance)
+ v, _ := instanceResult.GetMetadata()["aaa"]
+ assert.Equal(t, "bbb", v)
+
+ // test dispatcher event
+ //err = serviceDiscovery.DispatchEventByServiceName(instanceResult.GetServiceName())
+ //assert.Nil(t, err)
+
+ // test AddListener
+ err = serviceDiscovery.AddListener(®istry.ServiceInstancesChangedListener{ServiceName: instance.GetServiceName()})
+ assert.Nil(t, err)
+ err = serviceDiscovery.Unregister(instance)
+ assert.Nil(t, err)
+ timer := time.NewTimer(time.Second * 10)
+ select {
+ case <-eventDispatcher.Notify:
+ assert.NotNil(t, eventDispatcher.Event)
+ break
+ case <-timer.C:
+ assert.Fail(t, "")
+ break
+ }
+}
+
+func prepareData() {
+ config.GetBaseConfig().ServiceDiscoveries[testName] = &config.ServiceDiscoveryConfig{
+ Protocol: "consul",
+ RemoteRef: testName,
+ }
+
+ config.GetBaseConfig().Remotes[testName] = &config.RemoteConfig{
+ Address: fmt.Sprintf("%s:%d", registryHost, registryPort),
+ }
+}
+func prepareService() (registry.ServiceInstance, common.URL) {
+ id := "id"
+
+ registryUrl, _ := common.NewURL(protocol + "://" + providerHost + ":" + strconv.Itoa(providerPort) + "/" + service + "?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&consul-check-pass-interval=" + strconv.Itoa(consulCheckPassInterval) + "&consul-deregister-critical-service-after=" + consulDeregisterCriticalServiceAfter + "&" +
+ "consul-watch-timeout=" + strconv.Itoa(consulWatchTimeout))
+
+ return ®istry.DefaultServiceInstance{
+ Id: id,
+ ServiceName: service,
+ Host: registryHost,
+ Port: registryPort,
+ Enable: true,
+ Healthy: true,
+ Metadata: nil,
+ }, registryUrl
+}
+
+type MockEventDispatcher struct {
+ Notify chan struct{}
+ Event observer.Event
+}
+
+// AddEventListener do nothing
+func (m MockEventDispatcher) AddEventListener(listener observer.EventListener) {
Review comment:
- use pointer receiver `*MockEventDispatcher`
- modify all methods below to use pointer receiver
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] AlexStocks commented on a change in pull request #701: consul service discovery
Posted by GitBox <gi...@apache.org>.
AlexStocks commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r469138048
##########
File path: registry/event/event_publishing_service_discovery.go
##########
@@ -34,6 +39,7 @@ import (
// Publish some event about service discovery
type EventPublishingServiceDiscovery struct {
serviceDiscovery registry.ServiceDiscovery
+ once sync.Once
Review comment:
u add this var just for `epsd.serviceDiscovery.Initialize`. so u may need to change its name which is not so common, IMO.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] zhangshen023 commented on a change in pull request #701: consul service discovery
Posted by GitBox <gi...@apache.org>.
zhangshen023 commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r471214572
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,431 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ instance, ok := instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ initLock.Lock()
+ defer initLock.Unlock()
+
+ // double check
+ instance, ok = instanceMap[name]
Review comment:
I am also in doubt.There are same codes in nacos,zookeeper
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] zouyx commented on a change in pull request #701: consul service discovery
Posted by GitBox <gi...@apache.org>.
zouyx commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r471207092
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,431 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ instance, ok := instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ initLock.Lock()
+ defer initLock.Unlock()
+
+ // double check
+ instance, ok = instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ pageSize := 20
+ if remoteConfig.Params != nil {
+ if tmp, OK := remoteConfig.Params[PageSize]; OK {
+ intTmp, err := strconv.Atoi(tmp)
+ if err == nil && intTmp > 20 {
+ pageSize = intTmp
+ }
+ }
+ }
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ PageSize: pageSize,
+ ttl: make(map[string]chan struct{}),
+ }, nil
+}
+
+// nacosServiceDiscovery is the implementation of service discovery based on nacos.
+// There is a problem, the go client for nacos does not support the id field.
+// we will use the metadata to store the id of ServiceInstance
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ PageSize int
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl map[string]chan struct{}
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) Init(registryURL common.URL) error {
+ csd.serviceUrl = registryURL
+ csd.checkPassInterval = registryURL.GetParamInt(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL)
+ csd.tag = registryURL.GetParam(QUERY_TAG, "")
+ csd.tags = strings.Split(registryURL.GetParam("tags", ""), ",")
+ aclToken := registryURL.GetParam(ACL_TOKEN, "")
+ csd.Config = &consul.Config{Address: csd.address, Token: aclToken}
+ client, err := consul.NewClient(csd.Config)
+ if err != nil {
+ return perrors.WithMessage(err, "create consul client failed.")
+ }
+ csd.consulClient = client
+ return nil
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd *consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ for _, t := range csd.ttl {
+ close(t)
+ }
+ csd.ttl = nil
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ return csd.registerTtl(instance)
+}
+
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+ checkID := buildID(instance)
+
+ stopChan := make(chan struct{})
+ csd.ttl[buildID(instance)] = stopChan
+
+ period := time.Duration(csd.checkPassInterval/8) * time.Millisecond
+ timer := time.NewTimer(period)
+ go func() {
+ for {
+ select {
+ case <-timer.C:
+ timer.Reset(period)
+ err := csd.consulClient.Agent().PassTTL(checkID, "")
+ if err != nil {
+ logger.Warnf("pass ttl heartbeat fail:%v", err)
+ break
+ }
+ logger.Debugf("passed ttl heartbeat for %s", checkID)
+ break
+ case <-stopChan:
+ logger.Info("ttl %s for service %s is stopped", checkID, instance.GetServiceName())
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Update(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Warnf("unregister instance %s fail:%v", instance.GetServiceName(), err)
+ }
+ return csd.consulClient.Agent().ServiceRegister(ins)
+}
+
+func (csd *consulServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Errorf("unregister service instance %s,error: %v", instance.GetId(), err)
+ return err
+ }
+ stopChanel, ok := csd.ttl[buildID(instance)]
+ if ok {
+ close(stopChanel)
+ delete(csd.ttl, buildID(instance))
+ }
Review comment:
```suggestion
if !ok {
return error
}
```
I think you should change to not ok , because previous if block is not ok...
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,431 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
Review comment:
what's this variable scope? If private, change first char to lower case.
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,431 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ instance, ok := instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ initLock.Lock()
+ defer initLock.Unlock()
+
+ // double check
+ instance, ok = instanceMap[name]
Review comment:
I can not find where do you set this instance to `map`?
Do i miss something?
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,431 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ instance, ok := instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ initLock.Lock()
+ defer initLock.Unlock()
+
+ // double check
+ instance, ok = instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ pageSize := 20
+ if remoteConfig.Params != nil {
+ if tmp, OK := remoteConfig.Params[PageSize]; OK {
+ intTmp, err := strconv.Atoi(tmp)
+ if err == nil && intTmp > 20 {
+ pageSize = intTmp
+ }
+ }
+ }
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ PageSize: pageSize,
+ ttl: make(map[string]chan struct{}),
+ }, nil
+}
+
+// nacosServiceDiscovery is the implementation of service discovery based on nacos.
+// There is a problem, the go client for nacos does not support the id field.
+// we will use the metadata to store the id of ServiceInstance
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ PageSize int
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl map[string]chan struct{}
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) Init(registryURL common.URL) error {
+ csd.serviceUrl = registryURL
+ csd.checkPassInterval = registryURL.GetParamInt(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL)
+ csd.tag = registryURL.GetParam(QUERY_TAG, "")
+ csd.tags = strings.Split(registryURL.GetParam("tags", ""), ",")
+ aclToken := registryURL.GetParam(ACL_TOKEN, "")
+ csd.Config = &consul.Config{Address: csd.address, Token: aclToken}
+ client, err := consul.NewClient(csd.Config)
+ if err != nil {
+ return perrors.WithMessage(err, "create consul client failed.")
+ }
+ csd.consulClient = client
+ return nil
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd *consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ for _, t := range csd.ttl {
+ close(t)
+ }
+ csd.ttl = nil
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ return csd.registerTtl(instance)
+}
+
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+ checkID := buildID(instance)
+
+ stopChan := make(chan struct{})
+ csd.ttl[buildID(instance)] = stopChan
+
+ period := time.Duration(csd.checkPassInterval/8) * time.Millisecond
+ timer := time.NewTimer(period)
+ go func() {
+ for {
+ select {
+ case <-timer.C:
+ timer.Reset(period)
+ err := csd.consulClient.Agent().PassTTL(checkID, "")
+ if err != nil {
+ logger.Warnf("pass ttl heartbeat fail:%v", err)
+ break
+ }
+ logger.Debugf("passed ttl heartbeat for %s", checkID)
+ break
+ case <-stopChan:
+ logger.Info("ttl %s for service %s is stopped", checkID, instance.GetServiceName())
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Update(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Warnf("unregister instance %s fail:%v", instance.GetServiceName(), err)
Review comment:
Should you return error here?
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] beiwei30 commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
beiwei30 commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r485282509
##########
File path: registry/servicediscovery/service_discovery_registry_test.go
##########
@@ -126,6 +126,10 @@ func (m *mockServiceNameMapping) Get(serviceInterface string, group string, vers
type mockServiceDiscovery struct {
}
+func (m *mockServiceDiscovery) Init(registryURL common.URL) error {
Review comment:
remove this.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] zhangshen023 commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
zhangshen023 commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r487502590
##########
File path: registry/consul/service_discovery.go
##########
@@ -141,9 +137,10 @@ func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) e
consulClient *consul.Client
)
ins, _ := csd.buildRegisterInstance(instance)
- if consulClient, err = csd.getConsulClient(); err == nil {
- err = consulClient.Agent().ServiceRegister(ins)
+ if consulClient = csd.getConsulClient(); consulClient == nil {
+ return perrors.New("consul client is closed!")
Review comment:
lgtm
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] AlexStocks commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
AlexStocks commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r487374001
##########
File path: registry/consul/service_discovery_test.go
##########
@@ -0,0 +1,237 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "math/rand"
+ "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/common/extension"
+ "github.com/apache/dubbo-go/common/observer"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+ "github.com/apache/dubbo-go/remoting/consul"
+)
+
+var (
+ testName = "test"
+ consulCheckPassInterval = 17000
+ consulDeregisterCriticalServiceAfter = "20s"
+ consulWatchTimeout = 60000
+ registryURL = common.URL{
+ Path: "",
+ Username: "",
+ Password: "",
+ Methods: nil,
+ SubURL: nil,
Review comment:
delete the default value
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,430 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
Review comment:
add a rwlock to protect consulClient
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] AlexStocks commented on a change in pull request #701: consul service discovery
Posted by GitBox <gi...@apache.org>.
AlexStocks commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r469141446
##########
File path: registry/service_discovery.go
##########
@@ -34,6 +38,12 @@ type ServiceDiscovery interface {
// ----------------- lifecycle -------------------
+ /**
+ * Initializes the ServiceDiscovery
+ *
+ */
+ Initialize(registryURL common.URL) error
Review comment:
u add this func for `EventPublishingServiceDiscovery`. and then u add it to ServiceDiscovery interface. Pls think again.
what's more, the func name is so long which should be `Init`.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] AlexStocks commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
AlexStocks commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r487374001
##########
File path: registry/consul/service_discovery_test.go
##########
@@ -0,0 +1,237 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "math/rand"
+ "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/common/extension"
+ "github.com/apache/dubbo-go/common/observer"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+ "github.com/apache/dubbo-go/remoting/consul"
+)
+
+var (
+ testName = "test"
+ consulCheckPassInterval = 17000
+ consulDeregisterCriticalServiceAfter = "20s"
+ consulWatchTimeout = 60000
+ registryURL = common.URL{
+ Path: "",
+ Username: "",
+ Password: "",
+ Methods: nil,
+ SubURL: nil,
Review comment:
delete the default value
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,430 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
Review comment:
add a rwlock to protect consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
Review comment:
move it above the consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
Review comment:
why u do not use lock inside this func?
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
+ if csd.consulClient == nil {
+ return nil, perrors.New("consul client is destroyed or not ready!")
+ }
+ return csd.consulClient, nil
+}
Review comment:
add a blank line btw two funcs.
##########
File path: registry/consul/service_discovery_test.go
##########
@@ -0,0 +1,237 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "math/rand"
+ "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/common/extension"
+ "github.com/apache/dubbo-go/common/observer"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+ "github.com/apache/dubbo-go/remoting/consul"
+)
+
+var (
+ testName = "test"
+ consulCheckPassInterval = 17000
+ consulDeregisterCriticalServiceAfter = "20s"
+ consulWatchTimeout = 60000
+ registryURL = common.URL{
+ Path: "",
+ Username: "",
+ Password: "",
+ Methods: nil,
+ SubURL: nil,
Review comment:
delete the default value
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,430 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
Review comment:
add a rwlock to protect consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
Review comment:
move it above the consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
Review comment:
why u do not use lock inside this func?
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
+ if csd.consulClient == nil {
+ return nil, perrors.New("consul client is destroyed or not ready!")
+ }
+ return csd.consulClient, nil
+}
Review comment:
add a blank line btw two funcs.
##########
File path: registry/consul/service_discovery_test.go
##########
@@ -0,0 +1,237 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "math/rand"
+ "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/common/extension"
+ "github.com/apache/dubbo-go/common/observer"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+ "github.com/apache/dubbo-go/remoting/consul"
+)
+
+var (
+ testName = "test"
+ consulCheckPassInterval = 17000
+ consulDeregisterCriticalServiceAfter = "20s"
+ consulWatchTimeout = 60000
+ registryURL = common.URL{
+ Path: "",
+ Username: "",
+ Password: "",
+ Methods: nil,
+ SubURL: nil,
Review comment:
delete the default value
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,430 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
Review comment:
add a rwlock to protect consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
Review comment:
move it above the consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
Review comment:
why u do not use lock inside this func?
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
+ if csd.consulClient == nil {
+ return nil, perrors.New("consul client is destroyed or not ready!")
+ }
+ return csd.consulClient, nil
+}
Review comment:
add a blank line btw two funcs.
##########
File path: registry/consul/service_discovery_test.go
##########
@@ -0,0 +1,237 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "math/rand"
+ "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/common/extension"
+ "github.com/apache/dubbo-go/common/observer"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+ "github.com/apache/dubbo-go/remoting/consul"
+)
+
+var (
+ testName = "test"
+ consulCheckPassInterval = 17000
+ consulDeregisterCriticalServiceAfter = "20s"
+ consulWatchTimeout = 60000
+ registryURL = common.URL{
+ Path: "",
+ Username: "",
+ Password: "",
+ Methods: nil,
+ SubURL: nil,
Review comment:
delete the default value
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,430 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
Review comment:
add a rwlock to protect consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
Review comment:
move it above the consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
Review comment:
why u do not use lock inside this func?
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
+ if csd.consulClient == nil {
+ return nil, perrors.New("consul client is destroyed or not ready!")
+ }
+ return csd.consulClient, nil
+}
Review comment:
add a blank line btw two funcs.
##########
File path: registry/consul/service_discovery_test.go
##########
@@ -0,0 +1,237 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "math/rand"
+ "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/common/extension"
+ "github.com/apache/dubbo-go/common/observer"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+ "github.com/apache/dubbo-go/remoting/consul"
+)
+
+var (
+ testName = "test"
+ consulCheckPassInterval = 17000
+ consulDeregisterCriticalServiceAfter = "20s"
+ consulWatchTimeout = 60000
+ registryURL = common.URL{
+ Path: "",
+ Username: "",
+ Password: "",
+ Methods: nil,
+ SubURL: nil,
Review comment:
delete the default value
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,430 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
Review comment:
add a rwlock to protect consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
Review comment:
move it above the consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
Review comment:
why u do not use lock inside this func?
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
+ if csd.consulClient == nil {
+ return nil, perrors.New("consul client is destroyed or not ready!")
+ }
+ return csd.consulClient, nil
+}
Review comment:
add a blank line btw two funcs.
##########
File path: registry/consul/service_discovery_test.go
##########
@@ -0,0 +1,237 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "math/rand"
+ "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/common/extension"
+ "github.com/apache/dubbo-go/common/observer"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+ "github.com/apache/dubbo-go/remoting/consul"
+)
+
+var (
+ testName = "test"
+ consulCheckPassInterval = 17000
+ consulDeregisterCriticalServiceAfter = "20s"
+ consulWatchTimeout = 60000
+ registryURL = common.URL{
+ Path: "",
+ Username: "",
+ Password: "",
+ Methods: nil,
+ SubURL: nil,
Review comment:
delete the default value
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,430 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
Review comment:
add a rwlock to protect consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
Review comment:
move it above the consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
Review comment:
why u do not use lock inside this func?
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
+ if csd.consulClient == nil {
+ return nil, perrors.New("consul client is destroyed or not ready!")
+ }
+ return csd.consulClient, nil
+}
Review comment:
add a blank line btw two funcs.
##########
File path: registry/consul/service_discovery_test.go
##########
@@ -0,0 +1,237 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "math/rand"
+ "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/common/extension"
+ "github.com/apache/dubbo-go/common/observer"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+ "github.com/apache/dubbo-go/remoting/consul"
+)
+
+var (
+ testName = "test"
+ consulCheckPassInterval = 17000
+ consulDeregisterCriticalServiceAfter = "20s"
+ consulWatchTimeout = 60000
+ registryURL = common.URL{
+ Path: "",
+ Username: "",
+ Password: "",
+ Methods: nil,
+ SubURL: nil,
Review comment:
delete the default value
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,430 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
Review comment:
add a rwlock to protect consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
Review comment:
move it above the consulClient
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
Review comment:
why u do not use lock inside this func?
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,491 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+ watch_type = "type"
+ watch_type_service = "service"
+ watch_service = "service"
+ watch_passingonly = "passingonly"
+ watch_passingonly_true = true
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ clientLock: sync.RWMutex{},
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ clientLock sync.RWMutex
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+// nolint
+func (csd *consulServiceDiscovery) getConsulClient() (*consul.Client, error) {
+ if csd.consulClient == nil {
+ return nil, perrors.New("consul client is destroyed or not ready!")
+ }
+ return csd.consulClient, nil
+}
Review comment:
add a blank line btw two funcs.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] beiwei30 commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
beiwei30 commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r485282650
##########
File path: registry/zookeeper/service_discovery.go
##########
@@ -163,6 +163,10 @@ func (zksd *zookeeperServiceDiscovery) String() string {
return fmt.Sprintf("zookeeper-service-discovery[%s]", zksd.url)
}
+func (zksd *zookeeperServiceDiscovery) Init(registryURL common.URL) error {
Review comment:
remove this.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] AlexStocks commented on a change in pull request #701: consul service discovery
Posted by GitBox <gi...@apache.org>.
AlexStocks commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r469141583
##########
File path: registry/service_discovery.go
##########
@@ -34,6 +38,12 @@ type ServiceDiscovery interface {
// ----------------- lifecycle -------------------
+ /**
+ * Initializes the ServiceDiscovery
+ *
+ */
+ Initialize(registryURL common.URL) error
Review comment:
u add this func for `EventPublishingServiceDiscovery`. and then u add it to ServiceDiscovery interface. Pls think again.
what's more, the func name is so long which should be `Init`.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] codecov-commenter edited a comment on pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
codecov-commenter edited a comment on pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#issuecomment-673190849
# [Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=h1) Report
> Merging [#701](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=desc) into [develop](https://codecov.io/gh/apache/dubbo-go/commit/d542f6209b7ccd263d795138c1b33753284e3890?el=desc) will **increase** coverage by `0.35%`.
> The diff coverage is `75.00%`.
[](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=tree)
```diff
@@ Coverage Diff @@
## develop #701 +/- ##
===========================================
+ Coverage 63.69% 64.04% +0.35%
===========================================
Files 240 240
Lines 12986 12992 +6
===========================================
+ Hits 8271 8321 +50
+ Misses 3912 3866 -46
- Partials 803 805 +2
```
| [Impacted Files](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [registry/etcdv3/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvZXRjZHYzL3NlcnZpY2VfZGlzY292ZXJ5Lmdv) | `16.29% <0.00%> (-0.25%)` | :arrow_down: |
| [...gistry/event/event\_publishing\_service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvZXZlbnQvZXZlbnRfcHVibGlzaGluZ19zZXJ2aWNlX2Rpc2NvdmVyeS5nbw==) | `38.09% <0.00%> (-4.02%)` | :arrow_down: |
| [registry/nacos/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvbmFjb3Mvc2VydmljZV9kaXNjb3ZlcnkuZ28=) | `66.27% <0.00%> (-0.78%)` | :arrow_down: |
| [registry/zookeeper/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvem9va2VlcGVyL3NlcnZpY2VfZGlzY292ZXJ5Lmdv) | `82.35% <0.00%> (-0.99%)` | :arrow_down: |
| [registry/consul/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvY29uc3VsL3NlcnZpY2VfZGlzY292ZXJ5Lmdv) | `78.66% <78.66%> (ø)` | |
| [...try/servicediscovery/service\_discovery\_registry.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvc2VydmljZWRpc2NvdmVyeS9zZXJ2aWNlX2Rpc2NvdmVyeV9yZWdpc3RyeS5nbw==) | `15.66% <100.00%> (+3.74%)` | :arrow_up: |
| [config\_center/nacos/facade.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-Y29uZmlnX2NlbnRlci9uYWNvcy9mYWNhZGUuZ28=) | `81.25% <0.00%> (-9.38%)` | :arrow_down: |
| [config/registry\_config.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-Y29uZmlnL3JlZ2lzdHJ5X2NvbmZpZy5nbw==) | `80.64% <0.00%> (-3.23%)` | :arrow_down: |
| [cluster/cluster\_impl/failback\_cluster\_invoker.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-Y2x1c3Rlci9jbHVzdGVyX2ltcGwvZmFpbGJhY2tfY2x1c3Rlcl9pbnZva2VyLmdv) | `78.02% <0.00%> (-2.20%)` | :arrow_down: |
| [config\_center/nacos/client.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-Y29uZmlnX2NlbnRlci9uYWNvcy9jbGllbnQuZ28=) | `68.51% <0.00%> (-1.86%)` | :arrow_down: |
| ... and [23 more](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree-more) | |
------
[Continue to review full report at Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=footer). Last update [d542f62...55dfc25](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] gaoxinge commented on a change in pull request #701: consul service discovery
Posted by GitBox <gi...@apache.org>.
gaoxinge commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r467547354
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,440 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ "github.com/hashicorp/go-hclog"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+
+ instance, ok := instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ initLock.Lock()
+ defer initLock.Unlock()
+
+ // double check
+ instance, ok = instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ pageSize := 20
+ if remoteConfig.Params != nil {
+ if tmp, OK := remoteConfig.Params[PageSize]; OK {
+ intTmp, err := strconv.Atoi(tmp)
+ if err == nil && intTmp > 20 {
+ pageSize = intTmp
+ }
+ }
+ }
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ PageSize: pageSize,
+ ttl: make(map[string]chan struct{}),
+ }, nil
+}
+
+// nacosServiceDiscovery is the implementation of service discovery based on nacos.
+// There is a problem, the go client for nacos does not support the id field.
+// we will use the metadata to store the id of ServiceInstance
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ PageSize int
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl map[string]chan struct{}
+}
+
+func (csd *consulServiceDiscovery) Initialize(registryURL common.URL) error {
+ csd.serviceUrl = registryURL
+ csd.checkPassInterval = registryURL.GetParamInt(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL)
+ csd.tag = registryURL.GetParam(QUERY_TAG, "")
+ csd.tags = strings.Split(registryURL.GetParam("tags", ""), ",")
+ aclToken := registryURL.GetParam(ACL_TOKEN, "")
+ config := &consul.Config{Address: csd.address, Token: aclToken}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return perrors.WithMessage(err, "create consul client failed.")
+ }
+ csd.consulClient = client
+ return nil
+}
+func (csd consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ for _, t := range csd.ttl {
+ close(t)
+ }
+ csd.ttl = nil
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ csd.registerTtl(instance)
+
+ return nil
Review comment:
It may be better to return` csd.registerTtl(instance)` directly.
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,440 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ "github.com/hashicorp/go-hclog"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+
+ instance, ok := instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ initLock.Lock()
+ defer initLock.Unlock()
+
+ // double check
+ instance, ok = instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ pageSize := 20
+ if remoteConfig.Params != nil {
+ if tmp, OK := remoteConfig.Params[PageSize]; OK {
+ intTmp, err := strconv.Atoi(tmp)
+ if err == nil && intTmp > 20 {
+ pageSize = intTmp
+ }
+ }
+ }
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ PageSize: pageSize,
+ ttl: make(map[string]chan struct{}),
+ }, nil
+}
+
+// nacosServiceDiscovery is the implementation of service discovery based on nacos.
+// There is a problem, the go client for nacos does not support the id field.
+// we will use the metadata to store the id of ServiceInstance
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ PageSize int
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl map[string]chan struct{}
+}
+
+func (csd *consulServiceDiscovery) Initialize(registryURL common.URL) error {
+ csd.serviceUrl = registryURL
+ csd.checkPassInterval = registryURL.GetParamInt(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL)
+ csd.tag = registryURL.GetParam(QUERY_TAG, "")
+ csd.tags = strings.Split(registryURL.GetParam("tags", ""), ",")
+ aclToken := registryURL.GetParam(ACL_TOKEN, "")
+ config := &consul.Config{Address: csd.address, Token: aclToken}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return perrors.WithMessage(err, "create consul client failed.")
+ }
+ csd.consulClient = client
+ return nil
+}
+func (csd consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ for _, t := range csd.ttl {
+ close(t)
+ }
+ csd.ttl = nil
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ csd.registerTtl(instance)
+
+ return nil
+
+}
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+
Review comment:
Remove this blank line.
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,440 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ "github.com/hashicorp/go-hclog"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+
+ instance, ok := instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ initLock.Lock()
+ defer initLock.Unlock()
+
+ // double check
+ instance, ok = instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ pageSize := 20
+ if remoteConfig.Params != nil {
+ if tmp, OK := remoteConfig.Params[PageSize]; OK {
+ intTmp, err := strconv.Atoi(tmp)
+ if err == nil && intTmp > 20 {
+ pageSize = intTmp
+ }
+ }
+ }
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ PageSize: pageSize,
+ ttl: make(map[string]chan struct{}),
+ }, nil
+}
+
+// nacosServiceDiscovery is the implementation of service discovery based on nacos.
+// There is a problem, the go client for nacos does not support the id field.
+// we will use the metadata to store the id of ServiceInstance
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ PageSize int
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl map[string]chan struct{}
+}
+
+func (csd *consulServiceDiscovery) Initialize(registryURL common.URL) error {
+ csd.serviceUrl = registryURL
+ csd.checkPassInterval = registryURL.GetParamInt(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL)
+ csd.tag = registryURL.GetParam(QUERY_TAG, "")
+ csd.tags = strings.Split(registryURL.GetParam("tags", ""), ",")
+ aclToken := registryURL.GetParam(ACL_TOKEN, "")
+ config := &consul.Config{Address: csd.address, Token: aclToken}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return perrors.WithMessage(err, "create consul client failed.")
+ }
+ csd.consulClient = client
+ return nil
+}
+func (csd consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ for _, t := range csd.ttl {
+ close(t)
+ }
+ csd.ttl = nil
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ csd.registerTtl(instance)
+
+ return nil
+
+}
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+
+ checkID := buildID(instance)
+
+ stopChan := make(chan struct{})
+ csd.ttl[buildID(instance)] = stopChan
+
+ period := time.Duration(csd.checkPassInterval/8) * time.Millisecond
+ timer := time.NewTimer(period)
+ go func() {
+ for {
+ select {
+ case <-timer.C:
+ timer.Reset(period)
+ err := csd.consulClient.Agent().PassTTL(checkID, "")
+ if err != nil {
+ logger.Warnf("pass ttl heartbeat fail:%v", err)
+ break
+ }
+ logger.Debugf("passed ttl heartbeat for %s", checkID)
+ break
+ case <-stopChan:
+ logger.Info("ttl %s for service %s is stopped", checkID, instance.GetServiceName())
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (csd consulServiceDiscovery) Update(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Warnf("unregister instance %s fail:%v", instance.GetServiceName(), err)
+ }
+ return csd.consulClient.Agent().ServiceRegister(ins)
+}
+
+func (csd consulServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Errorf("unregister service instance %s,error: %v", instance.GetId(), err)
+ return err
+ }
+ stopChanel, ok := csd.ttl[buildID(instance)]
+ if ok {
+ close(stopChanel)
+ delete(csd.ttl, buildID(instance))
+ }
+ return nil
+}
+
+func (csd consulServiceDiscovery) GetDefaultPageSize() int {
+ return csd.PageSize
+}
+
+func (csd consulServiceDiscovery) GetServices() *gxset.HashSet {
+
+ var res = gxset.NewSet()
+ services, _, err := csd.consulClient.Catalog().Services(nil)
+ if err != nil {
+ logger.Errorf("get services,error: %v", err)
+ return res
+ }
+
+ for service, _ := range services {
+ res.Add(service)
+ }
+ return res
+
+}
+
+func (csd consulServiceDiscovery) GetInstances(serviceName string) []registry.ServiceInstance {
+ waitTime := csd.serviceUrl.GetParamInt(WATCH_TIMEOUT, DEFAULT_WATCH_TIMEOUT) / 1000
+ instances, _, err := csd.consulClient.Health().Service(serviceName, csd.tag, true, &consul.QueryOptions{
+ WaitTime: time.Duration(waitTime),
+ })
+ if err != nil {
+ logger.Errorf("get instances for service %s,error: %v", serviceName, err)
+ return nil
+ }
+
+ res := make([]registry.ServiceInstance, 0, len(instances))
+ for _, ins := range instances {
+ metadata := ins.Service.Meta
+
+ // enable status
+ enableStr := metadata[Enable]
+ delete(metadata, Enable)
+ enable, _ := strconv.ParseBool(enableStr)
+
+ // health status
+ status := ins.Checks.AggregatedStatus()
+ healthy := false
+ if status == consul.HealthPassing {
+ healthy = true
+ }
+ res = append(res, ®istry.DefaultServiceInstance{
+ Id: ins.Service.ID,
+ ServiceName: ins.Service.Service,
+ Host: ins.Service.Address,
+ Port: ins.Service.Port,
+ Enable: enable,
+ Healthy: healthy,
+ Metadata: metadata,
+ })
+ }
+
+ return res
+}
+
+func (csd consulServiceDiscovery) GetInstancesByPage(serviceName string, offset int, pageSize int) gxpage.Pager {
+ all := csd.GetInstances(serviceName)
+ res := make([]interface{}, 0, pageSize)
+ for i := offset; i < len(all) && i < offset+pageSize; i++ {
+ res = append(res, all[i])
+ }
+ return gxpage.New(offset, pageSize, res, len(all))
+}
+
+func (csd consulServiceDiscovery) GetHealthyInstancesByPage(serviceName string, offset int, pageSize int, healthy bool) gxpage.Pager {
+ all := csd.GetInstances(serviceName)
+ res := make([]interface{}, 0, pageSize)
+ // could not use res = all[a:b] here because the res should be []interface{}, not []ServiceInstance
+ var (
+ i = offset
+ count = 0
+ )
+ for i < len(all) && count < pageSize {
+ ins := all[i]
+ if ins.IsHealthy() == healthy {
+ res = append(res, all[i])
+ count++
+ }
+ i++
+ }
+ return gxpage.New(offset, pageSize, res, len(all))
+}
+
+func (csd consulServiceDiscovery) GetRequestInstances(serviceNames []string, offset int, requestedSize int) map[string]gxpage.Pager {
+ res := make(map[string]gxpage.Pager, len(serviceNames))
+ for _, name := range serviceNames {
+ res[name] = csd.GetInstancesByPage(name, offset, requestedSize)
+ }
+ return res
+}
+
+func (csd consulServiceDiscovery) AddListener(listener *registry.ServiceInstancesChangedListener) error {
+
+ params := make(map[string]interface{}, 8)
+ params["type"] = "service"
+ params["service"] = listener.ServiceName
+ params["passingonly"] = true
+ plan, err := watch.Parse(params)
+ if err != nil {
+ logger.Errorf("add listener for service %s,error:%v", listener.ServiceName, err)
+ return err
+ }
+
+ hcLogger := hclog.New(&hclog.LoggerOptions{
+ Name: "watch",
+ Output: plan.LogOutput,
+ })
+ plan.Handler = func(idx uint64, raw interface{}) {
+ services, ok := raw.([]*consul.ServiceEntry)
+ if !ok {
+ err = perrors.New("handler get non ServiceEntry type parameter")
+ return
+ }
+ instances := make([]registry.ServiceInstance, 0, len(services))
+ for _, ins := range services {
+ metadata := ins.Service.Meta
+
+ // enable status
+ enableStr := metadata[Enable]
+ delete(metadata, Enable)
+ enable, _ := strconv.ParseBool(enableStr)
+
+ // health status
+ status := ins.Checks.AggregatedStatus()
+ healthy := false
+ if status == consul.HealthPassing {
+ healthy = true
+ }
+ instances = append(instances, ®istry.DefaultServiceInstance{
+ Id: ins.Service.ID,
+ ServiceName: ins.Service.Service,
+ Host: ins.Service.Address,
+ Port: ins.Service.Port,
+ Enable: enable,
+ Healthy: healthy,
+ Metadata: metadata,
+ })
+ }
+ e := csd.DispatchEventForInstances(listener.ServiceName, instances)
+ if e != nil {
+ logger.Errorf("Dispatching event got exception, service name: %s, err: %v", listener.ServiceName, err)
+ }
+ }
+ go func() {
+ err = plan.RunWithClientAndHclog(csd.consulClient, hcLogger)
+ if err != nil {
+ logger.Error("consul plan run failure!error:%v", err)
+ }
+ }()
+ return nil
+}
+
+func (csd consulServiceDiscovery) DispatchEventByServiceName(serviceName string) error {
+ return csd.DispatchEventForInstances(serviceName, csd.GetInstances(serviceName))
+}
+
+func (csd consulServiceDiscovery) DispatchEventForInstances(serviceName string, instances []registry.ServiceInstance) error {
+ return csd.DispatchEvent(registry.NewServiceInstancesChangedEvent(serviceName, instances))
+}
+
+func (csd consulServiceDiscovery) DispatchEvent(event *registry.ServiceInstancesChangedEvent) error {
+ extension.GetGlobalDispatcher().Dispatch(event)
+ return nil
+}
+
+func (csd consulServiceDiscovery) buildRegisterInstance(instance registry.ServiceInstance) (*consul.AgentServiceRegistration, error) {
+ metadata := instance.GetMetadata()
+ if metadata == nil {
+ metadata = make(map[string]string, 1)
+ }
+ metadata[Enable] = strconv.FormatBool(instance.IsEnable())
+
+ // check
+ check := csd.buildCheck(instance)
+
+ return &consul.AgentServiceRegistration{
+ ID: buildID(instance),
+ Name: instance.GetServiceName(),
+ Port: instance.GetPort(),
+ Address: instance.GetHost(),
+ Meta: metadata,
+ Check: &check,
+ }, nil
+}
+
+func (csd consulServiceDiscovery) buildCheck(instance registry.ServiceInstance) consul.AgentServiceCheck {
+
Review comment:
As above.
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,440 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ "github.com/hashicorp/go-hclog"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+
+ instance, ok := instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ initLock.Lock()
+ defer initLock.Unlock()
+
+ // double check
+ instance, ok = instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ pageSize := 20
+ if remoteConfig.Params != nil {
+ if tmp, OK := remoteConfig.Params[PageSize]; OK {
+ intTmp, err := strconv.Atoi(tmp)
+ if err == nil && intTmp > 20 {
+ pageSize = intTmp
+ }
+ }
+ }
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ PageSize: pageSize,
+ ttl: make(map[string]chan struct{}),
+ }, nil
+}
+
+// nacosServiceDiscovery is the implementation of service discovery based on nacos.
+// There is a problem, the go client for nacos does not support the id field.
+// we will use the metadata to store the id of ServiceInstance
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ PageSize int
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl map[string]chan struct{}
+}
+
+func (csd *consulServiceDiscovery) Initialize(registryURL common.URL) error {
+ csd.serviceUrl = registryURL
+ csd.checkPassInterval = registryURL.GetParamInt(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL)
+ csd.tag = registryURL.GetParam(QUERY_TAG, "")
+ csd.tags = strings.Split(registryURL.GetParam("tags", ""), ",")
+ aclToken := registryURL.GetParam(ACL_TOKEN, "")
+ config := &consul.Config{Address: csd.address, Token: aclToken}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return perrors.WithMessage(err, "create consul client failed.")
+ }
+ csd.consulClient = client
+ return nil
+}
+func (csd consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ for _, t := range csd.ttl {
+ close(t)
+ }
+ csd.ttl = nil
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ csd.registerTtl(instance)
+
+ return nil
+
+}
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+
+ checkID := buildID(instance)
+
+ stopChan := make(chan struct{})
+ csd.ttl[buildID(instance)] = stopChan
+
+ period := time.Duration(csd.checkPassInterval/8) * time.Millisecond
+ timer := time.NewTimer(period)
+ go func() {
+ for {
+ select {
+ case <-timer.C:
+ timer.Reset(period)
+ err := csd.consulClient.Agent().PassTTL(checkID, "")
+ if err != nil {
+ logger.Warnf("pass ttl heartbeat fail:%v", err)
+ break
+ }
+ logger.Debugf("passed ttl heartbeat for %s", checkID)
+ break
+ case <-stopChan:
+ logger.Info("ttl %s for service %s is stopped", checkID, instance.GetServiceName())
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (csd consulServiceDiscovery) Update(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Warnf("unregister instance %s fail:%v", instance.GetServiceName(), err)
+ }
+ return csd.consulClient.Agent().ServiceRegister(ins)
+}
+
+func (csd consulServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Errorf("unregister service instance %s,error: %v", instance.GetId(), err)
+ return err
+ }
+ stopChanel, ok := csd.ttl[buildID(instance)]
+ if ok {
+ close(stopChanel)
+ delete(csd.ttl, buildID(instance))
+ }
+ return nil
+}
+
+func (csd consulServiceDiscovery) GetDefaultPageSize() int {
+ return csd.PageSize
+}
+
+func (csd consulServiceDiscovery) GetServices() *gxset.HashSet {
+
+ var res = gxset.NewSet()
+ services, _, err := csd.consulClient.Catalog().Services(nil)
+ if err != nil {
+ logger.Errorf("get services,error: %v", err)
+ return res
+ }
+
+ for service, _ := range services {
+ res.Add(service)
+ }
+ return res
+
+}
+
+func (csd consulServiceDiscovery) GetInstances(serviceName string) []registry.ServiceInstance {
+ waitTime := csd.serviceUrl.GetParamInt(WATCH_TIMEOUT, DEFAULT_WATCH_TIMEOUT) / 1000
+ instances, _, err := csd.consulClient.Health().Service(serviceName, csd.tag, true, &consul.QueryOptions{
+ WaitTime: time.Duration(waitTime),
+ })
+ if err != nil {
+ logger.Errorf("get instances for service %s,error: %v", serviceName, err)
+ return nil
+ }
+
+ res := make([]registry.ServiceInstance, 0, len(instances))
+ for _, ins := range instances {
+ metadata := ins.Service.Meta
+
+ // enable status
+ enableStr := metadata[Enable]
+ delete(metadata, Enable)
+ enable, _ := strconv.ParseBool(enableStr)
+
+ // health status
+ status := ins.Checks.AggregatedStatus()
+ healthy := false
+ if status == consul.HealthPassing {
+ healthy = true
+ }
+ res = append(res, ®istry.DefaultServiceInstance{
+ Id: ins.Service.ID,
+ ServiceName: ins.Service.Service,
+ Host: ins.Service.Address,
+ Port: ins.Service.Port,
+ Enable: enable,
+ Healthy: healthy,
+ Metadata: metadata,
+ })
+ }
+
+ return res
+}
+
+func (csd consulServiceDiscovery) GetInstancesByPage(serviceName string, offset int, pageSize int) gxpage.Pager {
+ all := csd.GetInstances(serviceName)
+ res := make([]interface{}, 0, pageSize)
+ for i := offset; i < len(all) && i < offset+pageSize; i++ {
+ res = append(res, all[i])
+ }
+ return gxpage.New(offset, pageSize, res, len(all))
+}
+
+func (csd consulServiceDiscovery) GetHealthyInstancesByPage(serviceName string, offset int, pageSize int, healthy bool) gxpage.Pager {
+ all := csd.GetInstances(serviceName)
+ res := make([]interface{}, 0, pageSize)
+ // could not use res = all[a:b] here because the res should be []interface{}, not []ServiceInstance
+ var (
+ i = offset
+ count = 0
+ )
+ for i < len(all) && count < pageSize {
+ ins := all[i]
+ if ins.IsHealthy() == healthy {
+ res = append(res, all[i])
+ count++
+ }
+ i++
+ }
+ return gxpage.New(offset, pageSize, res, len(all))
+}
+
+func (csd consulServiceDiscovery) GetRequestInstances(serviceNames []string, offset int, requestedSize int) map[string]gxpage.Pager {
+ res := make(map[string]gxpage.Pager, len(serviceNames))
+ for _, name := range serviceNames {
+ res[name] = csd.GetInstancesByPage(name, offset, requestedSize)
+ }
+ return res
+}
+
+func (csd consulServiceDiscovery) AddListener(listener *registry.ServiceInstancesChangedListener) error {
+
Review comment:
As above.
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,440 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ "github.com/hashicorp/go-hclog"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+
+ instance, ok := instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ initLock.Lock()
+ defer initLock.Unlock()
+
+ // double check
+ instance, ok = instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ pageSize := 20
+ if remoteConfig.Params != nil {
+ if tmp, OK := remoteConfig.Params[PageSize]; OK {
+ intTmp, err := strconv.Atoi(tmp)
+ if err == nil && intTmp > 20 {
+ pageSize = intTmp
+ }
+ }
+ }
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ PageSize: pageSize,
+ ttl: make(map[string]chan struct{}),
+ }, nil
+}
+
+// nacosServiceDiscovery is the implementation of service discovery based on nacos.
+// There is a problem, the go client for nacos does not support the id field.
+// we will use the metadata to store the id of ServiceInstance
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ PageSize int
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl map[string]chan struct{}
+}
+
+func (csd *consulServiceDiscovery) Initialize(registryURL common.URL) error {
+ csd.serviceUrl = registryURL
+ csd.checkPassInterval = registryURL.GetParamInt(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL)
+ csd.tag = registryURL.GetParam(QUERY_TAG, "")
+ csd.tags = strings.Split(registryURL.GetParam("tags", ""), ",")
+ aclToken := registryURL.GetParam(ACL_TOKEN, "")
+ config := &consul.Config{Address: csd.address, Token: aclToken}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return perrors.WithMessage(err, "create consul client failed.")
+ }
+ csd.consulClient = client
+ return nil
+}
+func (csd consulServiceDiscovery) String() string {
Review comment:
- Add a blank line before the `String()` function.
- It may be better to use pointer type `*consulServiceDiscovery`.
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,440 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ "github.com/hashicorp/go-hclog"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+
Review comment:
Remove this blank line.
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,440 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ "github.com/hashicorp/go-hclog"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+
+ instance, ok := instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ initLock.Lock()
+ defer initLock.Unlock()
+
+ // double check
+ instance, ok = instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ pageSize := 20
+ if remoteConfig.Params != nil {
+ if tmp, OK := remoteConfig.Params[PageSize]; OK {
+ intTmp, err := strconv.Atoi(tmp)
+ if err == nil && intTmp > 20 {
+ pageSize = intTmp
+ }
+ }
+ }
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ PageSize: pageSize,
+ ttl: make(map[string]chan struct{}),
+ }, nil
+}
+
+// nacosServiceDiscovery is the implementation of service discovery based on nacos.
+// There is a problem, the go client for nacos does not support the id field.
+// we will use the metadata to store the id of ServiceInstance
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ PageSize int
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl map[string]chan struct{}
+}
+
+func (csd *consulServiceDiscovery) Initialize(registryURL common.URL) error {
+ csd.serviceUrl = registryURL
+ csd.checkPassInterval = registryURL.GetParamInt(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL)
+ csd.tag = registryURL.GetParam(QUERY_TAG, "")
+ csd.tags = strings.Split(registryURL.GetParam("tags", ""), ",")
+ aclToken := registryURL.GetParam(ACL_TOKEN, "")
+ config := &consul.Config{Address: csd.address, Token: aclToken}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return perrors.WithMessage(err, "create consul client failed.")
+ }
+ csd.consulClient = client
+ return nil
+}
+func (csd consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ for _, t := range csd.ttl {
+ close(t)
+ }
+ csd.ttl = nil
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ csd.registerTtl(instance)
+
+ return nil
+
+}
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+
+ checkID := buildID(instance)
+
+ stopChan := make(chan struct{})
+ csd.ttl[buildID(instance)] = stopChan
+
+ period := time.Duration(csd.checkPassInterval/8) * time.Millisecond
+ timer := time.NewTimer(period)
+ go func() {
+ for {
+ select {
+ case <-timer.C:
+ timer.Reset(period)
+ err := csd.consulClient.Agent().PassTTL(checkID, "")
+ if err != nil {
+ logger.Warnf("pass ttl heartbeat fail:%v", err)
+ break
+ }
+ logger.Debugf("passed ttl heartbeat for %s", checkID)
+ break
+ case <-stopChan:
+ logger.Info("ttl %s for service %s is stopped", checkID, instance.GetServiceName())
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (csd consulServiceDiscovery) Update(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Warnf("unregister instance %s fail:%v", instance.GetServiceName(), err)
+ }
+ return csd.consulClient.Agent().ServiceRegister(ins)
+}
+
+func (csd consulServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Errorf("unregister service instance %s,error: %v", instance.GetId(), err)
+ return err
+ }
+ stopChanel, ok := csd.ttl[buildID(instance)]
+ if ok {
+ close(stopChanel)
+ delete(csd.ttl, buildID(instance))
+ }
+ return nil
+}
+
+func (csd consulServiceDiscovery) GetDefaultPageSize() int {
+ return csd.PageSize
+}
+
+func (csd consulServiceDiscovery) GetServices() *gxset.HashSet {
+
Review comment:
As above.
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,440 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ "github.com/hashicorp/go-hclog"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+
+ instance, ok := instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ initLock.Lock()
+ defer initLock.Unlock()
+
+ // double check
+ instance, ok = instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ pageSize := 20
+ if remoteConfig.Params != nil {
+ if tmp, OK := remoteConfig.Params[PageSize]; OK {
+ intTmp, err := strconv.Atoi(tmp)
+ if err == nil && intTmp > 20 {
+ pageSize = intTmp
+ }
+ }
+ }
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ PageSize: pageSize,
+ ttl: make(map[string]chan struct{}),
+ }, nil
+}
+
+// nacosServiceDiscovery is the implementation of service discovery based on nacos.
+// There is a problem, the go client for nacos does not support the id field.
+// we will use the metadata to store the id of ServiceInstance
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ PageSize int
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl map[string]chan struct{}
+}
+
+func (csd *consulServiceDiscovery) Initialize(registryURL common.URL) error {
+ csd.serviceUrl = registryURL
+ csd.checkPassInterval = registryURL.GetParamInt(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL)
+ csd.tag = registryURL.GetParam(QUERY_TAG, "")
+ csd.tags = strings.Split(registryURL.GetParam("tags", ""), ",")
+ aclToken := registryURL.GetParam(ACL_TOKEN, "")
+ config := &consul.Config{Address: csd.address, Token: aclToken}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return perrors.WithMessage(err, "create consul client failed.")
+ }
+ csd.consulClient = client
+ return nil
+}
+func (csd consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ for _, t := range csd.ttl {
+ close(t)
+ }
+ csd.ttl = nil
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ csd.registerTtl(instance)
+
+ return nil
+
+}
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+
+ checkID := buildID(instance)
+
+ stopChan := make(chan struct{})
+ csd.ttl[buildID(instance)] = stopChan
+
+ period := time.Duration(csd.checkPassInterval/8) * time.Millisecond
+ timer := time.NewTimer(period)
+ go func() {
+ for {
+ select {
+ case <-timer.C:
+ timer.Reset(period)
+ err := csd.consulClient.Agent().PassTTL(checkID, "")
+ if err != nil {
+ logger.Warnf("pass ttl heartbeat fail:%v", err)
+ break
+ }
+ logger.Debugf("passed ttl heartbeat for %s", checkID)
+ break
+ case <-stopChan:
+ logger.Info("ttl %s for service %s is stopped", checkID, instance.GetServiceName())
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (csd consulServiceDiscovery) Update(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Warnf("unregister instance %s fail:%v", instance.GetServiceName(), err)
+ }
+ return csd.consulClient.Agent().ServiceRegister(ins)
+}
+
+func (csd consulServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Errorf("unregister service instance %s,error: %v", instance.GetId(), err)
+ return err
+ }
+ stopChanel, ok := csd.ttl[buildID(instance)]
+ if ok {
+ close(stopChanel)
+ delete(csd.ttl, buildID(instance))
+ }
+ return nil
+}
+
+func (csd consulServiceDiscovery) GetDefaultPageSize() int {
+ return csd.PageSize
+}
+
+func (csd consulServiceDiscovery) GetServices() *gxset.HashSet {
+
+ var res = gxset.NewSet()
+ services, _, err := csd.consulClient.Catalog().Services(nil)
+ if err != nil {
+ logger.Errorf("get services,error: %v", err)
+ return res
+ }
+
+ for service, _ := range services {
+ res.Add(service)
+ }
+ return res
+
+}
+
+func (csd consulServiceDiscovery) GetInstances(serviceName string) []registry.ServiceInstance {
+ waitTime := csd.serviceUrl.GetParamInt(WATCH_TIMEOUT, DEFAULT_WATCH_TIMEOUT) / 1000
+ instances, _, err := csd.consulClient.Health().Service(serviceName, csd.tag, true, &consul.QueryOptions{
+ WaitTime: time.Duration(waitTime),
+ })
+ if err != nil {
+ logger.Errorf("get instances for service %s,error: %v", serviceName, err)
+ return nil
+ }
+
+ res := make([]registry.ServiceInstance, 0, len(instances))
+ for _, ins := range instances {
+ metadata := ins.Service.Meta
+
+ // enable status
+ enableStr := metadata[Enable]
+ delete(metadata, Enable)
+ enable, _ := strconv.ParseBool(enableStr)
+
+ // health status
+ status := ins.Checks.AggregatedStatus()
+ healthy := false
+ if status == consul.HealthPassing {
+ healthy = true
+ }
+ res = append(res, ®istry.DefaultServiceInstance{
+ Id: ins.Service.ID,
+ ServiceName: ins.Service.Service,
+ Host: ins.Service.Address,
+ Port: ins.Service.Port,
+ Enable: enable,
+ Healthy: healthy,
+ Metadata: metadata,
+ })
+ }
+
+ return res
+}
+
+func (csd consulServiceDiscovery) GetInstancesByPage(serviceName string, offset int, pageSize int) gxpage.Pager {
+ all := csd.GetInstances(serviceName)
+ res := make([]interface{}, 0, pageSize)
+ for i := offset; i < len(all) && i < offset+pageSize; i++ {
+ res = append(res, all[i])
+ }
+ return gxpage.New(offset, pageSize, res, len(all))
+}
+
+func (csd consulServiceDiscovery) GetHealthyInstancesByPage(serviceName string, offset int, pageSize int, healthy bool) gxpage.Pager {
+ all := csd.GetInstances(serviceName)
+ res := make([]interface{}, 0, pageSize)
+ // could not use res = all[a:b] here because the res should be []interface{}, not []ServiceInstance
+ var (
+ i = offset
+ count = 0
+ )
+ for i < len(all) && count < pageSize {
+ ins := all[i]
+ if ins.IsHealthy() == healthy {
+ res = append(res, all[i])
+ count++
+ }
+ i++
+ }
+ return gxpage.New(offset, pageSize, res, len(all))
+}
+
+func (csd consulServiceDiscovery) GetRequestInstances(serviceNames []string, offset int, requestedSize int) map[string]gxpage.Pager {
+ res := make(map[string]gxpage.Pager, len(serviceNames))
+ for _, name := range serviceNames {
+ res[name] = csd.GetInstancesByPage(name, offset, requestedSize)
+ }
+ return res
+}
+
+func (csd consulServiceDiscovery) AddListener(listener *registry.ServiceInstancesChangedListener) error {
+
+ params := make(map[string]interface{}, 8)
+ params["type"] = "service"
+ params["service"] = listener.ServiceName
+ params["passingonly"] = true
+ plan, err := watch.Parse(params)
+ if err != nil {
+ logger.Errorf("add listener for service %s,error:%v", listener.ServiceName, err)
+ return err
+ }
+
+ hcLogger := hclog.New(&hclog.LoggerOptions{
+ Name: "watch",
+ Output: plan.LogOutput,
+ })
+ plan.Handler = func(idx uint64, raw interface{}) {
+ services, ok := raw.([]*consul.ServiceEntry)
+ if !ok {
+ err = perrors.New("handler get non ServiceEntry type parameter")
+ return
+ }
+ instances := make([]registry.ServiceInstance, 0, len(services))
+ for _, ins := range services {
+ metadata := ins.Service.Meta
+
+ // enable status
+ enableStr := metadata[Enable]
+ delete(metadata, Enable)
+ enable, _ := strconv.ParseBool(enableStr)
+
+ // health status
+ status := ins.Checks.AggregatedStatus()
+ healthy := false
+ if status == consul.HealthPassing {
+ healthy = true
+ }
+ instances = append(instances, ®istry.DefaultServiceInstance{
+ Id: ins.Service.ID,
+ ServiceName: ins.Service.Service,
+ Host: ins.Service.Address,
+ Port: ins.Service.Port,
+ Enable: enable,
+ Healthy: healthy,
+ Metadata: metadata,
+ })
+ }
+ e := csd.DispatchEventForInstances(listener.ServiceName, instances)
+ if e != nil {
+ logger.Errorf("Dispatching event got exception, service name: %s, err: %v", listener.ServiceName, err)
+ }
+ }
+ go func() {
+ err = plan.RunWithClientAndHclog(csd.consulClient, hcLogger)
+ if err != nil {
+ logger.Error("consul plan run failure!error:%v", err)
+ }
+ }()
+ return nil
+}
+
+func (csd consulServiceDiscovery) DispatchEventByServiceName(serviceName string) error {
+ return csd.DispatchEventForInstances(serviceName, csd.GetInstances(serviceName))
+}
+
+func (csd consulServiceDiscovery) DispatchEventForInstances(serviceName string, instances []registry.ServiceInstance) error {
+ return csd.DispatchEvent(registry.NewServiceInstancesChangedEvent(serviceName, instances))
+}
+
+func (csd consulServiceDiscovery) DispatchEvent(event *registry.ServiceInstancesChangedEvent) error {
+ extension.GetGlobalDispatcher().Dispatch(event)
+ return nil
+}
+
+func (csd consulServiceDiscovery) buildRegisterInstance(instance registry.ServiceInstance) (*consul.AgentServiceRegistration, error) {
+ metadata := instance.GetMetadata()
+ if metadata == nil {
+ metadata = make(map[string]string, 1)
+ }
+ metadata[Enable] = strconv.FormatBool(instance.IsEnable())
+
+ // check
+ check := csd.buildCheck(instance)
+
+ return &consul.AgentServiceRegistration{
+ ID: buildID(instance),
+ Name: instance.GetServiceName(),
+ Port: instance.GetPort(),
+ Address: instance.GetHost(),
+ Meta: metadata,
+ Check: &check,
+ }, nil
+}
+
+func (csd consulServiceDiscovery) buildCheck(instance registry.ServiceInstance) consul.AgentServiceCheck {
+
+ deregister, ok := instance.GetMetadata()[DEREGISTER_AFTER]
+ if !ok || deregister == "" {
+ deregister = DEFAULT_DEREGISTER_TIME
+ }
+ return consul.AgentServiceCheck{
+ CheckID: buildID(instance),
+ TTL: strconv.FormatInt(csd.checkPassInterval/1000, 10) + "s",
+ DeregisterCriticalServiceAfter: deregister,
+ }
+}
+
+func buildID(instance registry.ServiceInstance) string {
+
Review comment:
As above.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] zhangshen023 commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
zhangshen023 commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r485591951
##########
File path: registry/servicediscovery/service_discovery_registry.go
##########
@@ -124,7 +124,8 @@ func creatServiceDiscovery(url *common.URL) (registry.ServiceDiscovery, error) {
if err != nil {
return nil, perrors.WithMessage(err, "Create service discovery fialed")
}
- return event.NewEventPublishingServiceDiscovery(originServiceDiscovery), nil
+ serviceDiscovery := event.NewEventPublishingServiceDiscovery(originServiceDiscovery)
Review comment:
ok,I'll revert this
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] zhangshen023 commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
zhangshen023 commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r485274362
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,422 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+)
+
+var (
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl sync.Map
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) Init(registryURL common.URL) error {
Review comment:
lgtm,i got fixed
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] AlexStocks commented on a change in pull request #701: consul service discovery
Posted by GitBox <gi...@apache.org>.
AlexStocks commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r469142180
##########
File path: registry/event/event_publishing_service_deiscovery_test.go
##########
@@ -116,6 +117,10 @@ func (tel *TestServiceInstancePreRegisteredEventListener) GetEventType() reflect
type ServiceDiscoveryA struct {
}
+func (msd *ServiceDiscoveryA) Initialize(registryURL common.URL) error {
Review comment:
IMO, u add this func interface just for
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] zhangshen023 commented on a change in pull request #701: consul service discovery
Posted by GitBox <gi...@apache.org>.
zhangshen023 commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r471217015
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,431 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ instance, ok := instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ initLock.Lock()
+ defer initLock.Unlock()
+
+ // double check
+ instance, ok = instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ pageSize := 20
+ if remoteConfig.Params != nil {
+ if tmp, OK := remoteConfig.Params[PageSize]; OK {
+ intTmp, err := strconv.Atoi(tmp)
+ if err == nil && intTmp > 20 {
+ pageSize = intTmp
+ }
+ }
+ }
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ PageSize: pageSize,
+ ttl: make(map[string]chan struct{}),
+ }, nil
+}
+
+// nacosServiceDiscovery is the implementation of service discovery based on nacos.
+// There is a problem, the go client for nacos does not support the id field.
+// we will use the metadata to store the id of ServiceInstance
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ PageSize int
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl map[string]chan struct{}
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) Init(registryURL common.URL) error {
+ csd.serviceUrl = registryURL
+ csd.checkPassInterval = registryURL.GetParamInt(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL)
+ csd.tag = registryURL.GetParam(QUERY_TAG, "")
+ csd.tags = strings.Split(registryURL.GetParam("tags", ""), ",")
+ aclToken := registryURL.GetParam(ACL_TOKEN, "")
+ csd.Config = &consul.Config{Address: csd.address, Token: aclToken}
+ client, err := consul.NewClient(csd.Config)
+ if err != nil {
+ return perrors.WithMessage(err, "create consul client failed.")
+ }
+ csd.consulClient = client
+ return nil
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd *consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ for _, t := range csd.ttl {
+ close(t)
+ }
+ csd.ttl = nil
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ return csd.registerTtl(instance)
+}
+
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+ checkID := buildID(instance)
+
+ stopChan := make(chan struct{})
+ csd.ttl[buildID(instance)] = stopChan
+
+ period := time.Duration(csd.checkPassInterval/8) * time.Millisecond
+ timer := time.NewTimer(period)
+ go func() {
+ for {
+ select {
+ case <-timer.C:
+ timer.Reset(period)
+ err := csd.consulClient.Agent().PassTTL(checkID, "")
+ if err != nil {
+ logger.Warnf("pass ttl heartbeat fail:%v", err)
+ break
+ }
+ logger.Debugf("passed ttl heartbeat for %s", checkID)
+ break
+ case <-stopChan:
+ logger.Info("ttl %s for service %s is stopped", checkID, instance.GetServiceName())
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Update(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Warnf("unregister instance %s fail:%v", instance.GetServiceName(), err)
+ }
+ return csd.consulClient.Agent().ServiceRegister(ins)
+}
+
+func (csd *consulServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Errorf("unregister service instance %s,error: %v", instance.GetId(), err)
+ return err
+ }
+ stopChanel, ok := csd.ttl[buildID(instance)]
+ if ok {
+ close(stopChanel)
+ delete(csd.ttl, buildID(instance))
+ }
Review comment:
i think it does not affect the main process even though it is not OK.I just add a warn log here
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] beiwei30 commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
beiwei30 commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r484749982
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,422 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+)
+
+var (
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl sync.Map
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) Init(registryURL common.URL) error {
Review comment:
It looks like 'registryURL' is dup with 'config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)'. I believe they serve the same purpose, so my question is, should we continue to stick to config.RemoteConfig or should we switch to registryURL, since it will impact all impls of service discovery.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] zouyx commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
zouyx commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r482725036
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,421 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+)
+
+var (
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ ttl: make(map[string]chan struct{}),
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl map[string]chan struct{}
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) Init(registryURL common.URL) error {
+ csd.serviceUrl = registryURL
+ csd.checkPassInterval = registryURL.GetParamInt(constant.CHECK_PASS_INTERVAL, constant.DEFAULT_CHECK_PASS_INTERVAL)
+ csd.tag = registryURL.GetParam(constant.QUERY_TAG, "")
+ csd.tags = strings.Split(registryURL.GetParam("tags", ""), ",")
+ aclToken := registryURL.GetParam(constant.ACL_TOKEN, "")
+ csd.Config = &consul.Config{Address: csd.address, Token: aclToken}
+ client, err := consul.NewClient(csd.Config)
+ if err != nil {
+ return perrors.WithMessage(err, "create consul client failed.")
+ }
+ csd.consulClient = client
+ return nil
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd *consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ for _, t := range csd.ttl {
+ close(t)
+ }
+ csd.ttl = nil
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ logger.Errorf("consul register the instance %s fail:%v", instance.GetServiceName(), err)
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ return csd.registerTtl(instance)
+}
+
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+ checkID := buildID(instance)
+
+ stopChan := make(chan struct{})
+ csd.ttl[buildID(instance)] = stopChan
+
+ period := time.Duration(csd.checkPassInterval/8) * time.Millisecond
+ timer := time.NewTimer(period)
+ go func() {
+ for {
+ select {
+ case <-timer.C:
+ timer.Reset(period)
+ err := csd.consulClient.Agent().PassTTL(fmt.Sprintf("service:%s", checkID), "")
+ if err != nil {
+ logger.Warnf("pass ttl heartbeat fail:%v", err)
+ break
+ }
+ logger.Debugf("passed ttl heartbeat for %s", checkID)
+ break
+ case <-stopChan:
+ logger.Info("ttl %s for service %s is stopped", checkID, instance.GetServiceName())
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Update(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Warnf("unregister instance %s fail:%v", instance.GetServiceName(), err)
+ }
+ return csd.consulClient.Agent().ServiceRegister(ins)
+}
+
+func (csd *consulServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Errorf("unregister service instance %s,error: %v", instance.GetId(), err)
+ return err
+ }
+ stopChanel, ok := csd.ttl[buildID(instance)]
+ if !ok {
+ logger.Warnf("ttl for service instance %s didn't exist", instance.GetId())
+ return nil
+ }
+ close(stopChanel)
+ delete(csd.ttl, buildID(instance))
+ return nil
Review comment:
The same to `Destory` method
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,421 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+)
+
+var (
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ ttl: make(map[string]chan struct{}),
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl map[string]chan struct{}
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) Init(registryURL common.URL) error {
+ csd.serviceUrl = registryURL
+ csd.checkPassInterval = registryURL.GetParamInt(constant.CHECK_PASS_INTERVAL, constant.DEFAULT_CHECK_PASS_INTERVAL)
+ csd.tag = registryURL.GetParam(constant.QUERY_TAG, "")
+ csd.tags = strings.Split(registryURL.GetParam("tags", ""), ",")
+ aclToken := registryURL.GetParam(constant.ACL_TOKEN, "")
+ csd.Config = &consul.Config{Address: csd.address, Token: aclToken}
+ client, err := consul.NewClient(csd.Config)
+ if err != nil {
+ return perrors.WithMessage(err, "create consul client failed.")
+ }
+ csd.consulClient = client
+ return nil
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd *consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ for _, t := range csd.ttl {
+ close(t)
+ }
+ csd.ttl = nil
+ return nil
Review comment:
Should add a lock and flag for this block .
For ensure it won‘t cause concurrency problem.
Because channel can‘t close twice.
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,421 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+)
+
+var (
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ ttl: make(map[string]chan struct{}),
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl map[string]chan struct{}
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) Init(registryURL common.URL) error {
+ csd.serviceUrl = registryURL
+ csd.checkPassInterval = registryURL.GetParamInt(constant.CHECK_PASS_INTERVAL, constant.DEFAULT_CHECK_PASS_INTERVAL)
+ csd.tag = registryURL.GetParam(constant.QUERY_TAG, "")
+ csd.tags = strings.Split(registryURL.GetParam("tags", ""), ",")
+ aclToken := registryURL.GetParam(constant.ACL_TOKEN, "")
+ csd.Config = &consul.Config{Address: csd.address, Token: aclToken}
+ client, err := consul.NewClient(csd.Config)
+ if err != nil {
+ return perrors.WithMessage(err, "create consul client failed.")
+ }
+ csd.consulClient = client
+ return nil
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd *consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ for _, t := range csd.ttl {
+ close(t)
+ }
+ csd.ttl = nil
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ logger.Errorf("consul register the instance %s fail:%v", instance.GetServiceName(), err)
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ return csd.registerTtl(instance)
+}
+
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+ checkID := buildID(instance)
+
+ stopChan := make(chan struct{})
+ csd.ttl[buildID(instance)] = stopChan
+
+ period := time.Duration(csd.checkPassInterval/8) * time.Millisecond
+ timer := time.NewTimer(period)
+ go func() {
+ for {
+ select {
+ case <-timer.C:
+ timer.Reset(period)
+ err := csd.consulClient.Agent().PassTTL(fmt.Sprintf("service:%s", checkID), "")
+ if err != nil {
+ logger.Warnf("pass ttl heartbeat fail:%v", err)
+ break
+ }
+ logger.Debugf("passed ttl heartbeat for %s", checkID)
+ break
+ case <-stopChan:
+ logger.Info("ttl %s for service %s is stopped", checkID, instance.GetServiceName())
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Update(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Warnf("unregister instance %s fail:%v", instance.GetServiceName(), err)
+ }
+ return csd.consulClient.Agent().ServiceRegister(ins)
+}
+
+func (csd *consulServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Errorf("unregister service instance %s,error: %v", instance.GetId(), err)
+ return err
+ }
+ stopChanel, ok := csd.ttl[buildID(instance)]
+ if !ok {
+ logger.Warnf("ttl for service instance %s didn't exist", instance.GetId())
+ return nil
+ }
+ close(stopChanel)
+ delete(csd.ttl, buildID(instance))
+ return nil
+}
+
+func (csd *consulServiceDiscovery) GetDefaultPageSize() int {
+ return registry.DefaultPageSize
+}
+
+func (csd *consulServiceDiscovery) GetServices() *gxset.HashSet {
+
+ var res = gxset.NewSet()
+ services, _, err := csd.consulClient.Catalog().Services(nil)
+ if err != nil {
+ logger.Errorf("get services,error: %v", err)
+ return res
+ }
+
+ for service, _ := range services {
+ res.Add(service)
+ }
+ return res
+
+}
+
+// encodeConsulMetadata because consul validate key strictly.
+func encodeConsulMetadata(metadata map[string]string) map[string]string {
+ consulMetadata := make(map[string]string, 8)
+ if metadata == nil {
+ return consulMetadata
+ }
+ encoder := base64.RawStdEncoding
+ for k, v := range metadata {
+ consulMetadata[encoder.EncodeToString([]byte(k))] = v
+ }
+ return consulMetadata
+}
+
+// nolint
+func decodeConsulMetadata(metadata map[string]string) map[string]string {
+ dubboMetadata := make(map[string]string, 8)
+ if metadata == nil {
+ return dubboMetadata
+ }
+ encoder := base64.RawStdEncoding
+ for k, v := range metadata {
+ kBytes, err := encoder.DecodeString(k)
+ if err != nil {
+ logger.Warnf("can not decoded consul metadata key %s", k)
+ continue
+ }
+ dubboMetadata[string(kBytes)] = v
+ }
+ return dubboMetadata
+}
+
+func (csd *consulServiceDiscovery) GetInstances(serviceName string) []registry.ServiceInstance {
+ waitTime := csd.serviceUrl.GetParamInt(constant.WATCH_TIMEOUT, constant.DEFAULT_WATCH_TIMEOUT) / 1000
+ instances, _, err := csd.consulClient.Health().Service(serviceName, csd.tag, true, &consul.QueryOptions{
+ WaitTime: time.Duration(waitTime),
+ })
+ if err != nil {
+ logger.Errorf("get instances for service %s,error: %v", serviceName, err)
+ return nil
+ }
+
+ res := make([]registry.ServiceInstance, 0, len(instances))
+ for _, ins := range instances {
+ metadata := ins.Service.Meta
+
+ // enable status
+ enableStr := metadata[enable]
+ delete(metadata, enable)
+ enable, _ := strconv.ParseBool(enableStr)
+ metadata = decodeConsulMetadata(metadata)
+
+ // health status
+ status := ins.Checks.AggregatedStatus()
+ healthy := false
+ if status == consul.HealthPassing {
+ healthy = true
+ }
+ res = append(res, ®istry.DefaultServiceInstance{
+ Id: ins.Service.ID,
+ ServiceName: ins.Service.Service,
+ Host: ins.Service.Address,
+ Port: ins.Service.Port,
+ Enable: enable,
+ Healthy: healthy,
+ Metadata: metadata,
+ })
+ }
+
+ return res
+}
+
+func (csd *consulServiceDiscovery) GetInstancesByPage(serviceName string, offset int, pageSize int) gxpage.Pager {
+ all := csd.GetInstances(serviceName)
+ res := make([]interface{}, 0, pageSize)
+ for i := offset; i < len(all) && i < offset+pageSize; i++ {
+ res = append(res, all[i])
+ }
+ return gxpage.New(offset, pageSize, res, len(all))
+}
+
+func (csd *consulServiceDiscovery) GetHealthyInstancesByPage(serviceName string, offset int, pageSize int, healthy bool) gxpage.Pager {
+ all := csd.GetInstances(serviceName)
+ res := make([]interface{}, 0, pageSize)
+ // could not use res = all[a:b] here because the res should be []interface{}, not []ServiceInstance
+ var (
+ i = offset
+ count = 0
+ )
+ for i < len(all) && count < pageSize {
+ ins := all[i]
+ if ins.IsHealthy() == healthy {
+ res = append(res, all[i])
+ count++
+ }
+ i++
+ }
+ return gxpage.New(offset, pageSize, res, len(all))
+}
+
+func (csd *consulServiceDiscovery) GetRequestInstances(serviceNames []string, offset int, requestedSize int) map[string]gxpage.Pager {
+ res := make(map[string]gxpage.Pager, len(serviceNames))
+ for _, name := range serviceNames {
+ res[name] = csd.GetInstancesByPage(name, offset, requestedSize)
+ }
+ return res
+}
+
+func (csd *consulServiceDiscovery) AddListener(listener *registry.ServiceInstancesChangedListener) error {
+
+ params := make(map[string]interface{}, 8)
+ params["type"] = "service"
+ params["service"] = listener.ServiceName
+ params["passingonly"] = true
+ plan, err := watch.Parse(params)
+ if err != nil {
+ logger.Errorf("add listener for service %s,error:%v", listener.ServiceName, err)
+ return err
+ }
+
+ plan.Handler = func(idx uint64, raw interface{}) {
+ services, ok := raw.([]*consul.ServiceEntry)
+ if !ok {
+ err = perrors.New("handler get non ServiceEntry type parameter")
+ return
+ }
+ instances := make([]registry.ServiceInstance, 0, len(services))
+ for _, ins := range services {
+ metadata := ins.Service.Meta
+
+ // enable status
+ enableStr := metadata[enable]
+ delete(metadata, enable)
+ enable, _ := strconv.ParseBool(enableStr)
+
+ // health status
+ status := ins.Checks.AggregatedStatus()
+ healthy := false
+ if status == consul.HealthPassing {
+ healthy = true
+ }
+ instances = append(instances, ®istry.DefaultServiceInstance{
+ Id: ins.Service.ID,
+ ServiceName: ins.Service.Service,
+ Host: ins.Service.Address,
+ Port: ins.Service.Port,
+ Enable: enable,
+ Healthy: healthy,
+ Metadata: metadata,
+ })
+ }
+ e := csd.DispatchEventForInstances(listener.ServiceName, instances)
+ if e != nil {
+ logger.Errorf("Dispatching event got exception, service name: %s, err: %v", listener.ServiceName, err)
+ }
+ }
+ go func() {
+ err = plan.RunWithConfig(csd.Config.Address, csd.Config)
+ if err != nil {
+ logger.Error("consul plan run failure!error:%v", err)
+ }
+ }()
+ return nil
+}
+
+func (csd *consulServiceDiscovery) DispatchEventByServiceName(serviceName string) error {
+ return csd.DispatchEventForInstances(serviceName, csd.GetInstances(serviceName))
+}
+
+func (csd *consulServiceDiscovery) DispatchEventForInstances(serviceName string, instances []registry.ServiceInstance) error {
+ return csd.DispatchEvent(registry.NewServiceInstancesChangedEvent(serviceName, instances))
+}
+
+func (csd *consulServiceDiscovery) DispatchEvent(event *registry.ServiceInstancesChangedEvent) error {
+ extension.GetGlobalDispatcher().Dispatch(event)
+ return nil
+}
+
+func (csd *consulServiceDiscovery) buildRegisterInstance(instance registry.ServiceInstance) (*consul.AgentServiceRegistration, error) {
+ metadata := instance.GetMetadata()
+ metadata = encodeConsulMetadata(metadata)
+ metadata[enable] = strconv.FormatBool(instance.IsEnable())
+ // check
+ check := csd.buildCheck(instance)
+
+ return &consul.AgentServiceRegistration{
+ ID: buildID(instance),
+ Name: instance.GetServiceName(),
+ Port: instance.GetPort(),
+ Address: instance.GetHost(),
+ Meta: metadata,
+ Check: &check,
+ }, nil
+}
+
+func (csd *consulServiceDiscovery) buildCheck(instance registry.ServiceInstance) consul.AgentServiceCheck {
+
+ deregister, ok := instance.GetMetadata()[constant.DEREGISTER_AFTER]
+ if !ok || deregister == "" {
Review comment:
```suggestion
if !ok || len(deregister)==0 {
```
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] zhangshen023 commented on pull request #701: consul service discovery
Posted by GitBox <gi...@apache.org>.
zhangshen023 commented on pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#issuecomment-670853917
@gaoxinge thanks, I've solved these problems
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] zhangshen023 commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
zhangshen023 commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r481758066
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,431 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ instance, ok := instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ initLock.Lock()
+ defer initLock.Unlock()
+
+ // double check
+ instance, ok = instanceMap[name]
Review comment:
deleted
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] AlexStocks commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
AlexStocks commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r487501931
##########
File path: registry/consul/service_discovery.go
##########
@@ -141,9 +137,10 @@ func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) e
consulClient *consul.Client
)
ins, _ := csd.buildRegisterInstance(instance)
- if consulClient, err = csd.getConsulClient(); err == nil {
- err = consulClient.Agent().ServiceRegister(ins)
+ if consulClient = csd.getConsulClient(); consulClient == nil {
+ return perrors.New("consul client is closed!")
Review comment:
var (
ErrConsulClientClosed = perrors.New("consul client is closed")
)
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] codecov-commenter commented on pull request #701: consul service discovery
Posted by GitBox <gi...@apache.org>.
codecov-commenter commented on pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#issuecomment-673190849
# [Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=h1) Report
> Merging [#701](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=desc) into [develop](https://codecov.io/gh/apache/dubbo-go/commit/12680fdab94cbfebb75d58b28f8b71addee7269a&el=desc) will **increase** coverage by `0.50%`.
> The diff coverage is `73.46%`.
[](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=tree)
```diff
@@ Coverage Diff @@
## develop #701 +/- ##
===========================================
+ Coverage 63.62% 64.13% +0.50%
===========================================
Files 238 239 +1
Lines 12355 12791 +436
===========================================
+ Hits 7861 8203 +342
- Misses 3733 3803 +70
- Partials 761 785 +24
```
| [Impacted Files](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [registry/etcdv3/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvZXRjZHYzL3NlcnZpY2VfZGlzY292ZXJ5Lmdv) | `16.29% <0.00%> (-0.25%)` | :arrow_down: |
| [...gistry/event/event\_publishing\_service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvZXZlbnQvZXZlbnRfcHVibGlzaGluZ19zZXJ2aWNlX2Rpc2NvdmVyeS5nbw==) | `38.09% <0.00%> (-4.02%)` | :arrow_down: |
| [registry/nacos/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvbmFjb3Mvc2VydmljZV9kaXNjb3ZlcnkuZ28=) | `66.27% <0.00%> (-2.44%)` | :arrow_down: |
| [registry/zookeeper/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvem9va2VlcGVyL3NlcnZpY2VfZGlzY292ZXJ5Lmdv) | `82.35% <0.00%> (-0.99%)` | :arrow_down: |
| [registry/consul/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvY29uc3VsL3NlcnZpY2VfZGlzY292ZXJ5Lmdv) | `76.95% <76.95%> (ø)` | |
| [...try/servicediscovery/service\_discovery\_registry.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvc2VydmljZWRpc2NvdmVyeS9zZXJ2aWNlX2Rpc2NvdmVyeV9yZWdpc3RyeS5nbw==) | `15.66% <100.00%> (+0.40%)` | :arrow_up: |
| [cluster/loadbalance/util.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-Y2x1c3Rlci9sb2FkYmFsYW5jZS91dGlsLmdv) | `66.66% <0.00%> (-19.05%)` | :arrow_down: |
| [filter/filter\_impl/metrics\_filter.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-ZmlsdGVyL2ZpbHRlcl9pbXBsL21ldHJpY3NfZmlsdGVyLmdv) | `86.36% <0.00%> (-13.64%)` | :arrow_down: |
| [common/yaml/yaml.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-Y29tbW9uL3lhbWwveWFtbC5nbw==) | `86.66% <0.00%> (-13.34%)` | :arrow_down: |
| [registry/nacos/registry.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvbmFjb3MvcmVnaXN0cnkuZ28=) | `50.32% <0.00%> (-9.06%)` | :arrow_down: |
| ... and [34 more](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree-more) | |
------
[Continue to review full report at Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=footer). Last update [12680fd...77eb76e](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] zouyx commented on a change in pull request #701: consul service discovery
Posted by GitBox <gi...@apache.org>.
zouyx commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r471237721
##########
File path: registry/consul/service_discovery.go
##########
@@ -219,15 +194,17 @@ func (csd *consulServiceDiscovery) Unregister(instance registry.ServiceInstance)
return err
}
stopChanel, ok := csd.ttl[buildID(instance)]
- if ok {
+ if !ok {
+ logger.Warnf("ttl for service instance %s didn't exist", instance.GetId())
+ } else {
close(stopChanel)
delete(csd.ttl, buildID(instance))
}
return nil
Review comment:
```suggestion
if !ok {
logger.Warnf("ttl for service instance %s didn't exist", instance.GetId())
return nil
}
close(stopChanel)
delete(csd.ttl, buildID(instance))
return nil
```
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] zhangshen023 commented on a change in pull request #701: consul service discovery
Posted by GitBox <gi...@apache.org>.
zhangshen023 commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r471215166
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,431 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ instance, ok := instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ initLock.Lock()
+ defer initLock.Unlock()
+
+ // double check
+ instance, ok = instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ pageSize := 20
+ if remoteConfig.Params != nil {
+ if tmp, OK := remoteConfig.Params[PageSize]; OK {
+ intTmp, err := strconv.Atoi(tmp)
+ if err == nil && intTmp > 20 {
+ pageSize = intTmp
+ }
+ }
+ }
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ PageSize: pageSize,
+ ttl: make(map[string]chan struct{}),
+ }, nil
+}
+
+// nacosServiceDiscovery is the implementation of service discovery based on nacos.
+// There is a problem, the go client for nacos does not support the id field.
+// we will use the metadata to store the id of ServiceInstance
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ PageSize int
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl map[string]chan struct{}
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) Init(registryURL common.URL) error {
+ csd.serviceUrl = registryURL
+ csd.checkPassInterval = registryURL.GetParamInt(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL)
+ csd.tag = registryURL.GetParam(QUERY_TAG, "")
+ csd.tags = strings.Split(registryURL.GetParam("tags", ""), ",")
+ aclToken := registryURL.GetParam(ACL_TOKEN, "")
+ csd.Config = &consul.Config{Address: csd.address, Token: aclToken}
+ client, err := consul.NewClient(csd.Config)
+ if err != nil {
+ return perrors.WithMessage(err, "create consul client failed.")
+ }
+ csd.consulClient = client
+ return nil
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd *consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ for _, t := range csd.ttl {
+ close(t)
+ }
+ csd.ttl = nil
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ return csd.registerTtl(instance)
+}
+
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+ checkID := buildID(instance)
+
+ stopChan := make(chan struct{})
+ csd.ttl[buildID(instance)] = stopChan
+
+ period := time.Duration(csd.checkPassInterval/8) * time.Millisecond
+ timer := time.NewTimer(period)
+ go func() {
+ for {
+ select {
+ case <-timer.C:
+ timer.Reset(period)
+ err := csd.consulClient.Agent().PassTTL(checkID, "")
+ if err != nil {
+ logger.Warnf("pass ttl heartbeat fail:%v", err)
+ break
+ }
+ logger.Debugf("passed ttl heartbeat for %s", checkID)
+ break
+ case <-stopChan:
+ logger.Info("ttl %s for service %s is stopped", checkID, instance.GetServiceName())
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Update(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Warnf("unregister instance %s fail:%v", instance.GetServiceName(), err)
Review comment:
i think it's OK. No matter how the service status was before.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] codecov-commenter edited a comment on pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
codecov-commenter edited a comment on pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#issuecomment-673190849
# [Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=h1) Report
> Merging [#701](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=desc) into [develop](https://codecov.io/gh/apache/dubbo-go/commit/bb197cc70d7810a017ac1c0e5addbf992e69a49b?el=desc) will **decrease** coverage by `0.02%`.
> The diff coverage is `78.30%`.
[](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=tree)
```diff
@@ Coverage Diff @@
## develop #701 +/- ##
===========================================
- Coverage 63.70% 63.68% -0.03%
===========================================
Files 240 245 +5
Lines 12977 13858 +881
===========================================
+ Hits 8267 8825 +558
- Misses 3911 4152 +241
- Partials 799 881 +82
```
| [Impacted Files](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [registry/consul/service\_discovery.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvY29uc3VsL3NlcnZpY2VfZGlzY292ZXJ5Lmdv) | `78.30% <78.30%> (ø)` | |
| [filter/filter\_impl/metrics\_filter.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-ZmlsdGVyL2ZpbHRlcl9pbXBsL21ldHJpY3NfZmlsdGVyLmdv) | `86.36% <0.00%> (-13.64%)` | :arrow_down: |
| [filter/filter\_impl/access\_log\_filter.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-ZmlsdGVyL2ZpbHRlcl9pbXBsL2FjY2Vzc19sb2dfZmlsdGVyLmdv) | `64.03% <0.00%> (-7.00%)` | :arrow_down: |
| [registry/directory/directory.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvZGlyZWN0b3J5L2RpcmVjdG9yeS5nbw==) | `74.76% <0.00%> (-6.39%)` | :arrow_down: |
| [common/proxy/proxy\_factory/default.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-Y29tbW9uL3Byb3h5L3Byb3h5X2ZhY3RvcnkvZGVmYXVsdC5nbw==) | `19.11% <0.00%> (-1.52%)` | :arrow_down: |
| [cluster/router/tag/tag\_router.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-Y2x1c3Rlci9yb3V0ZXIvdGFnL3RhZ19yb3V0ZXIuZ28=) | `75.15% <0.00%> (-0.31%)` | :arrow_down: |
| [protocol/dubbo/dubbo\_invoker.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cHJvdG9jb2wvZHViYm8vZHViYm9faW52b2tlci5nbw==) | `81.96% <0.00%> (-0.30%)` | :arrow_down: |
| [registry/protocol/protocol.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cmVnaXN0cnkvcHJvdG9jb2wvcHJvdG9jb2wuZ28=) | `78.24% <0.00%> (-0.24%)` | :arrow_down: |
| [protocol/dubbo/listener.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cHJvdG9jb2wvZHViYm8vbGlzdGVuZXIuZ28=) | `57.29% <0.00%> (-0.23%)` | :arrow_down: |
| [protocol/result.go](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree#diff-cHJvdG9jb2wvcmVzdWx0Lmdv) | `0.00% <0.00%> (ø)` | |
| ... and [11 more](https://codecov.io/gh/apache/dubbo-go/pull/701/diff?src=pr&el=tree-more) | |
------
[Continue to review full report at Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=footer). Last update [bb197cc...7662982](https://codecov.io/gh/apache/dubbo-go/pull/701?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] zouyx commented on a change in pull request #701: consul service discovery
Posted by GitBox <gi...@apache.org>.
zouyx commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r471207092
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,431 @@
+/*
+ * 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 consul
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ 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/extension"
+ "github.com/apache/dubbo-go/common/logger"
+ "github.com/apache/dubbo-go/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ PageSize = "pageSize"
+ Enable = "enable"
+)
+
+const (
+ CHECK_PASS_INTERVAL = "consul-check-pass-interval"
+ // default time-to-live in millisecond
+ DEFAULT_CHECK_PASS_INTERVAL = 16000
+ QUERY_TAG = "consul_query_tag"
+ ACL_TOKEN = "acl-token"
+ // default deregister critical server after
+ DEFAULT_DEREGISTER_TIME = "20s"
+ DEFAULT_WATCH_TIMEOUT = 60 * 1000
+ WATCH_TIMEOUT = "consul-watch-timeout"
+ DEREGISTER_AFTER = "consul-deregister-critical-service-after"
+)
+
+var (
+ // 16 would be enough. We won't use concurrentMap because in most cases, there are not race condition
+ instanceMap = make(map[string]registry.ServiceDiscovery, 16)
+ initLock sync.Mutex
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ instance, ok := instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ initLock.Lock()
+ defer initLock.Unlock()
+
+ // double check
+ instance, ok = instanceMap[name]
+ if ok {
+ return instance, nil
+ }
+
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ pageSize := 20
+ if remoteConfig.Params != nil {
+ if tmp, OK := remoteConfig.Params[PageSize]; OK {
+ intTmp, err := strconv.Atoi(tmp)
+ if err == nil && intTmp > 20 {
+ pageSize = intTmp
+ }
+ }
+ }
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ PageSize: pageSize,
+ ttl: make(map[string]chan struct{}),
+ }, nil
+}
+
+// nacosServiceDiscovery is the implementation of service discovery based on nacos.
+// There is a problem, the go client for nacos does not support the id field.
+// we will use the metadata to store the id of ServiceInstance
+type consulServiceDiscovery struct {
+ group string
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ PageSize int
+ serviceUrl common.URL
+ checkPassInterval int64
+ tag string
+ tags []string
+ address string
+ ttl map[string]chan struct{}
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) Init(registryURL common.URL) error {
+ csd.serviceUrl = registryURL
+ csd.checkPassInterval = registryURL.GetParamInt(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL)
+ csd.tag = registryURL.GetParam(QUERY_TAG, "")
+ csd.tags = strings.Split(registryURL.GetParam("tags", ""), ",")
+ aclToken := registryURL.GetParam(ACL_TOKEN, "")
+ csd.Config = &consul.Config{Address: csd.address, Token: aclToken}
+ client, err := consul.NewClient(csd.Config)
+ if err != nil {
+ return perrors.WithMessage(err, "create consul client failed.")
+ }
+ csd.consulClient = client
+ return nil
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd *consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ for _, t := range csd.ttl {
+ close(t)
+ }
+ csd.ttl = nil
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ return csd.registerTtl(instance)
+}
+
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+ checkID := buildID(instance)
+
+ stopChan := make(chan struct{})
+ csd.ttl[buildID(instance)] = stopChan
+
+ period := time.Duration(csd.checkPassInterval/8) * time.Millisecond
+ timer := time.NewTimer(period)
+ go func() {
+ for {
+ select {
+ case <-timer.C:
+ timer.Reset(period)
+ err := csd.consulClient.Agent().PassTTL(checkID, "")
+ if err != nil {
+ logger.Warnf("pass ttl heartbeat fail:%v", err)
+ break
+ }
+ logger.Debugf("passed ttl heartbeat for %s", checkID)
+ break
+ case <-stopChan:
+ logger.Info("ttl %s for service %s is stopped", checkID, instance.GetServiceName())
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Update(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Warnf("unregister instance %s fail:%v", instance.GetServiceName(), err)
+ }
+ return csd.consulClient.Agent().ServiceRegister(ins)
+}
+
+func (csd *consulServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Errorf("unregister service instance %s,error: %v", instance.GetId(), err)
+ return err
+ }
+ stopChanel, ok := csd.ttl[buildID(instance)]
+ if ok {
+ close(stopChanel)
+ delete(csd.ttl, buildID(instance))
+ }
Review comment:
```suggestion
if !ok {
return error
}
```
I think you should change to not ok , because previous `if` block is not ok...
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
[GitHub] [dubbo-go] zouyx commented on a change in pull request #701: Ftr: consul service discovery
Posted by GitBox <gi...@apache.org>.
zouyx commented on a change in pull request #701:
URL: https://github.com/apache/dubbo-go/pull/701#discussion_r485516557
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,431 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd *consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ csd.ttl.Range(func(key, t interface{}) bool {
+ close(t.(chan struct{}))
+ csd.ttl.Delete(key)
+ return true
+ })
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ logger.Errorf("consul register the instance %s fail:%v", instance.GetServiceName(), err)
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ return csd.registerTtl(instance)
+}
+
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+ checkID := buildID(instance)
+
+ stopChan := make(chan struct{})
+ csd.ttl.LoadOrStore(buildID(instance), stopChan)
+
+ period := time.Duration(csd.checkPassInterval/8) * time.Millisecond
+ timer := time.NewTimer(period)
+ go func() {
+ for {
+ select {
+ case <-timer.C:
+ timer.Reset(period)
+ err := csd.consulClient.Agent().PassTTL(fmt.Sprintf("service:%s", checkID), "")
+ if err != nil {
+ logger.Warnf("pass ttl heartbeat fail:%v", err)
+ break
+ }
+ logger.Debugf("passed ttl heartbeat for %s", checkID)
+ break
+ case <-stopChan:
+ logger.Info("ttl %s for service %s is stopped", checkID, instance.GetServiceName())
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Update(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Warnf("unregister instance %s fail:%v", instance.GetServiceName(), err)
+ }
+ return csd.consulClient.Agent().ServiceRegister(ins)
+}
+
+func (csd *consulServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Errorf("unregister service instance %s,error: %v", instance.GetId(), err)
+ return err
+ }
+
+ stopChanel, ok := csd.ttl.Load(buildID(instance))
+ if !ok {
+ logger.Warnf("ttl for service instance %s didn't exist", instance.GetId())
+ return nil
+ }
+ close(stopChanel.(chan struct{}))
+ csd.ttl.Delete(buildID(instance))
+ return nil
+}
+
+func (csd *consulServiceDiscovery) GetDefaultPageSize() int {
+ return registry.DefaultPageSize
+}
+
+func (csd *consulServiceDiscovery) GetServices() *gxset.HashSet {
+
+ var res = gxset.NewSet()
+ services, _, err := csd.consulClient.Catalog().Services(nil)
+ if err != nil {
+ logger.Errorf("get services,error: %v", err)
+ return res
+ }
+
+ for service, _ := range services {
+ res.Add(service)
+ }
+ return res
+
+}
+
+// encodeConsulMetadata because consul validate key strictly.
+func encodeConsulMetadata(metadata map[string]string) map[string]string {
+ consulMetadata := make(map[string]string, 8)
+ if metadata == nil {
+ return consulMetadata
+ }
Review comment:
```suggestion
if metadata == nil {
return consulMetadata
}
consulMetadata := make(map[string]string, len(metadata))
```
What about this style?
##########
File path: registry/consul/service_discovery.go
##########
@@ -0,0 +1,431 @@
+/*
+ * 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 consul
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+)
+
+import (
+ "github.com/dubbogo/gost/container/set"
+ "github.com/dubbogo/gost/page"
+ consul "github.com/hashicorp/consul/api"
+ "github.com/hashicorp/consul/api/watch"
+ perrors "github.com/pkg/errors"
+)
+
+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/config"
+ "github.com/apache/dubbo-go/registry"
+)
+
+const (
+ enable = "enable"
+)
+
+// init will put the service discovery into extension
+func init() {
+ extension.SetServiceDiscovery(constant.CONSUL_KEY, newConsulServiceDiscovery)
+}
+
+// newConsulServiceDiscovery will create new service discovery instance
+// use double-check pattern to reduce race condition
+func newConsulServiceDiscovery(name string) (registry.ServiceDiscovery, error) {
+ sdc, ok := config.GetBaseConfig().GetServiceDiscoveries(name)
+ if !ok || len(sdc.RemoteRef) == 0 {
+ return nil, perrors.New("could not init the instance because the config is invalid")
+ }
+
+ remoteConfig, ok := config.GetBaseConfig().GetRemoteConfig(sdc.RemoteRef)
+ if !ok {
+ return nil, perrors.New("could not find the remote config for name: " + sdc.RemoteRef)
+ }
+
+ descriptor := fmt.Sprintf("consul-service-discovery[%s]", remoteConfig.Address)
+
+ config := &consul.Config{Address: remoteConfig.Address, Token: remoteConfig.Params[constant.ACL_TOKEN]}
+ client, err := consul.NewClient(config)
+ if err != nil {
+ return nil, perrors.WithMessage(err, "create consul client failed.")
+ }
+
+ return &consulServiceDiscovery{
+ address: remoteConfig.Address,
+ descriptor: descriptor,
+ checkPassInterval: getCheckPassInterval(remoteConfig.Params),
+ Config: config,
+ tag: remoteConfig.Params[constant.QUERY_TAG],
+ consulClient: client,
+ deregisterCriticalServiceAfter: getDeregisterAfter(remoteConfig.Params),
+ }, nil
+}
+
+// consulServiceDiscovery is the implementation of service discovery based on consul.
+type consulServiceDiscovery struct {
+ // descriptor is a short string about the basic information of this instance
+ descriptor string
+ // Consul client.
+ consulClient *consul.Client
+ checkPassInterval int64
+ tag string
+ address string
+ deregisterCriticalServiceAfter string
+ ttl sync.Map
+ *consul.Config
+}
+
+func (csd *consulServiceDiscovery) String() string {
+ return csd.descriptor
+}
+
+func (csd *consulServiceDiscovery) Destroy() error {
+ csd.consulClient = nil
+ csd.ttl.Range(func(key, t interface{}) bool {
+ close(t.(chan struct{}))
+ csd.ttl.Delete(key)
+ return true
+ })
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Register(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceRegister(ins)
+ if err != nil {
+ logger.Errorf("consul register the instance %s fail:%v", instance.GetServiceName(), err)
+ return perrors.WithMessage(err, "consul could not register the instance. "+instance.GetServiceName())
+ }
+
+ return csd.registerTtl(instance)
+}
+
+func (csd *consulServiceDiscovery) registerTtl(instance registry.ServiceInstance) error {
+ checkID := buildID(instance)
+
+ stopChan := make(chan struct{})
+ csd.ttl.LoadOrStore(buildID(instance), stopChan)
+
+ period := time.Duration(csd.checkPassInterval/8) * time.Millisecond
+ timer := time.NewTimer(period)
+ go func() {
+ for {
+ select {
+ case <-timer.C:
+ timer.Reset(period)
+ err := csd.consulClient.Agent().PassTTL(fmt.Sprintf("service:%s", checkID), "")
+ if err != nil {
+ logger.Warnf("pass ttl heartbeat fail:%v", err)
+ break
+ }
+ logger.Debugf("passed ttl heartbeat for %s", checkID)
+ break
+ case <-stopChan:
+ logger.Info("ttl %s for service %s is stopped", checkID, instance.GetServiceName())
+ return
+ }
+ }
+ }()
+ return nil
+}
+
+func (csd *consulServiceDiscovery) Update(instance registry.ServiceInstance) error {
+ ins, _ := csd.buildRegisterInstance(instance)
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Warnf("unregister instance %s fail:%v", instance.GetServiceName(), err)
+ }
+ return csd.consulClient.Agent().ServiceRegister(ins)
+}
+
+func (csd *consulServiceDiscovery) Unregister(instance registry.ServiceInstance) error {
+ err := csd.consulClient.Agent().ServiceDeregister(buildID(instance))
+ if err != nil {
+ logger.Errorf("unregister service instance %s,error: %v", instance.GetId(), err)
+ return err
+ }
+
+ stopChanel, ok := csd.ttl.Load(buildID(instance))
+ if !ok {
+ logger.Warnf("ttl for service instance %s didn't exist", instance.GetId())
+ return nil
+ }
+ close(stopChanel.(chan struct{}))
+ csd.ttl.Delete(buildID(instance))
+ return nil
+}
+
+func (csd *consulServiceDiscovery) GetDefaultPageSize() int {
+ return registry.DefaultPageSize
+}
+
+func (csd *consulServiceDiscovery) GetServices() *gxset.HashSet {
+
+ var res = gxset.NewSet()
+ services, _, err := csd.consulClient.Catalog().Services(nil)
+ if err != nil {
+ logger.Errorf("get services,error: %v", err)
+ return res
+ }
+
+ for service, _ := range services {
+ res.Add(service)
+ }
+ return res
+
+}
+
+// encodeConsulMetadata because consul validate key strictly.
+func encodeConsulMetadata(metadata map[string]string) map[string]string {
+ consulMetadata := make(map[string]string, 8)
+ if metadata == nil {
+ return consulMetadata
+ }
+ encoder := base64.RawStdEncoding
+ for k, v := range metadata {
+ consulMetadata[encoder.EncodeToString([]byte(k))] = v
+ }
+ return consulMetadata
+}
+
+// nolint
+func decodeConsulMetadata(metadata map[string]string) map[string]string {
+ dubboMetadata := make(map[string]string, 8)
Review comment:
as above
##########
File path: registry/servicediscovery/service_discovery_registry.go
##########
@@ -124,7 +124,8 @@ func creatServiceDiscovery(url *common.URL) (registry.ServiceDiscovery, error) {
if err != nil {
return nil, perrors.WithMessage(err, "Create service discovery fialed")
}
- return event.NewEventPublishingServiceDiscovery(originServiceDiscovery), nil
+ serviceDiscovery := event.NewEventPublishingServiceDiscovery(originServiceDiscovery)
Review comment:
why change this line?
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org