You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by as...@apache.org on 2018/08/01 11:32:03 UTC
[incubator-servicecomb-service-center] branch master updated:
SCB-735 Add admin dump api (#396)
This is an automated email from the ASF dual-hosted git repository.
asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-service-center.git
The following commit(s) were added to refs/heads/master by this push:
new 7bf5c58 SCB-735 Add admin dump api (#396)
7bf5c58 is described below
commit 7bf5c582204d6237f3c3fe61d5d6f59986796a23
Author: little-cui <su...@qq.com>
AuthorDate: Wed Aug 1 19:31:59 2018 +0800
SCB-735 Add admin dump api (#396)
* SCB-735 Add admin dump api
* SCB-735 Add admin dump api
* SCB-735 Add admin dump api
* SCB-735 Add admin dump api
* SCB-735 Add admin dump api
* SCB-735 Add admin dump api
* Optimize code
* Optimize code
* Add find cross app UT
* Print accurate domain/project logs
* Add core UT
* Fix publisher dispatch job even if websocket handler is busy
* Add some UTs
* Optimize registry config
* Fix UT failure
* Optimize core package
* Bug fix: can not connect etcd with TLS
* Optimize server mux
* Add more metrics
* Update the swagger file
---
.gitignore | 2 +
etc/conf/app.conf | 14 +-
examples/service_center/ssl/cert_pwd | 1 +
examples/service_center/ssl/server.cer | 13 +
examples/service_center/ssl/server_key.pem | 18 +
examples/service_center/ssl/trust.cer | 13 +
frontend/main.go | 5 +-
.../mutex_test.go => integration/admin_test.go | 43 +-
integration/apis.go | 3 +
integration/health-metrics-grafana.json | 1772 +++++++++++++++++---
integration/instances_test.go | 6 +-
integration/microservices_test.go | 53 +-
integration/rules_test.go | 28 +-
integration/tags_test.go | 22 +-
main.go | 10 +-
pkg/chain/callback_test.go | 56 +
pkg/chain/chain_test.go | 150 +-
pkg/chain/handler.go | 4 +-
pkg/chain/invocation.go | 11 +-
pkg/etcdsync/etcdsync_suite_test.go | 15 +-
pkg/etcdsync/mutex.go | 126 +-
pkg/etcdsync/mutex_test.go | 39 +-
pkg/rest/client.go | 4 +-
pkg/rest/listener.go | 14 +-
pkg/rest/roa.go | 14 +-
pkg/rest/server.go | 51 +-
pkg/rpc/grpc.go | 2 +-
pkg/{async => task}/executor.go | 2 +-
pkg/{async/async.go => task/service.go} | 6 +-
pkg/{async/service.go => task/service_async.go} | 31 +-
pkg/{async/async_test.go => task/service_test.go} | 3 +-
pkg/{async => task}/task.go | 11 +-
pkg/tlsutil/tlsutil.go | 4 +-
pkg/tlsutil/tlsutil_test.go | 4 +-
pkg/util/context.go | 11 +-
pkg/util/context_test.go | 77 +
pkg/util/goroutines.go | 119 +-
pkg/util/goroutines_test.go | 12 +-
pkg/util/log.go | 57 +-
pkg/util/log_test.go | 23 +-
pkg/util/logrotate.go | 3 +
pkg/util/logrotate_test.go | 17 +
pkg/util/net.go | 18 +-
pkg/util/net_test.go | 47 +-
pkg/util/reflect.go | 88 +-
pkg/util/reflect_test.go | 59 +-
pkg/util/util.go | 82 +-
pkg/util/util_test.go | 42 +
pkg/util/{logrotate_test.go => uuid_test.go} | 9 +-
pkg/validate/url.go | 53 +-
pkg/validate/validator.go | 2 +-
scripts/prepare_env_ut.sh | 3 +-
scripts/ut_test_in_docker.sh | 11 +-
server/{broker/broker.go => admin/admin.go} | 4 +-
.../admin_suite_test.go} | 13 +-
main.go => server/admin/controller_v4.go | 33 +-
server/admin/model/dump.go | 185 ++
server/admin/service.go | 71 +
.../broker_suite_test.go => admin/service_test.go} | 45 +-
server/api.go | 10 +-
server/bootstrap/bootstrap.go | 5 +-
server/broker/broker.go | 2 +-
server/broker/broker_suite_test.go | 7 +-
server/broker/{ => brokerpb}/broker.pb.go | 2 +-
server/broker/{ => brokerpb}/broker.proto | 0
server/broker/controller.go | 19 +-
server/broker/{broker.go => controller_test.go} | 30 +-
server/broker/service.go | 201 +--
server/broker/service_test.go | 74 +-
server/broker/store.go | 28 +-
server/broker/util.go | 187 +--
server/core/backend/cache.go | 8 +-
server/core/backend/cache_kv.go | 22 +-
server/core/backend/cache_null.go | 15 +-
server/core/backend/cache_test.go | 57 +-
server/core/backend/cacher_kv.go | 69 +-
server/core/backend/cacher_kv_test.go | 340 ++++
server/core/backend/common.go | 40 +-
server/core/backend/config.go | 43 +-
server/core/backend/defer_instance.go | 18 +-
server/core/backend/defer_test.go | 14 +-
pkg/async/task.go => server/core/backend/entity.go | 12 +-
server/core/backend/entity_kv.go | 76 +
main.go => server/core/backend/entity_test.go | 35 +-
server/core/backend/event_proxy.go | 27 +-
.../core/backend/{extend_test.go => event_test.go} | 37 +-
server/core/backend/extend.go | 31 +-
server/core/backend/indexer.go | 68 -
.../core/backend/{indexer.go => indexer_base.go} | 61 +-
server/core/backend/indexer_kv.go | 86 +-
server/core/backend/indexer_test.go | 178 ++
server/core/backend/lease.go | 5 +-
.../backend/lease_test.go} | 45 +-
server/core/backend/listwatch.go | 123 +-
.../backend/{listwatch.go => listwatch_inner.go} | 73 +-
server/core/backend/listwatch_test.go | 119 ++
server/core/backend/metrics.go | 21 +-
.../backend/{extend_test.go => metrics_test.go} | 33 +-
server/core/backend/{kv.go => model.go} | 19 +-
server/core/backend/parser.go | 38 +-
server/core/backend/parser_test.go | 109 ++
.../task.go => server/core/backend/service.go | 12 +-
server/core/backend/store.go | 192 +--
server/core/backend/store_test.go | 141 ++
.../core/backend/watcher.go | 12 +-
server/core/backend/watcher_inner.go | 82 +
server/core/backend/watcher_test.go | 86 +
server/core/config.go | 18 +-
server/core/core.go | 6 +-
server/core/proto/services.go | 6 +-
server/core/swagger/v4.yaml | 163 +-
server/error/error.go | 4 +
server/govern/controller_v4.go | 34 -
server/govern/govern.go | 4 +-
server/govern/govern_suite_test.go | 11 +-
main.go => server/govern/graph.go | 44 +-
server/govern/service.go | 7 +-
server/govern/service_test.go | 77 +-
server/infra/quota/quota.go | 4 +-
server/infra/registry/registry.go | 55 +-
pkg/async/task.go => server/init/init.go | 10 +-
.../interceptor/interceptors_test.go | 70 +-
pkg/async/task.go => server/main.go | 10 +-
pkg/util/metric.go => server/metric/calculator.go | 38 +-
server/metric/common.go | 43 +-
server/metric/gatherer.go | 5 +-
server/metric/metrics.go | 2 +-
server/{service/event/event.go => metrics.go} | 26 +-
.../infra/registry/embededetcd/embededetcd.go | 23 +-
server/plugin/infra/registry/etcd/etcd.go | 333 ++--
server/plugin/infra/registry/etcd/etcd_test.go | 707 +++++++-
.../infra/registry/etcd/logger_test.go} | 51 +-
.../infra/registry/etcd/metrics.go} | 26 +-
server/plugin/infra/tls/buildin/tls_test.go | 5 +-
server/plugin/infra/tracing/buildin/buildin.go | 2 +-
.../plugin/infra/tracing/buildin/buildin_test.go | 75 +
server/plugin/infra/tracing/buildin/common.go | 3 +-
.../plugin/infra/tracing/buildin/file_collector.go | 38 +-
.../infra/tracing/buildin/file_collector_test.go | 27 +-
server/plugin/plugin.go | 56 +-
.../file_collector_test.go => plugin_test.go} | 64 +-
server/rest/controller/rest_util.go | 9 +-
server/rest/controller/v3/v3.go | 16 +-
server/rest/controller/v4/instance_controller.go | 3 +-
server/rest/controller/v4/main_controller.go | 2 +-
server/rest/controller/v4/v4.go | 16 +-
server/rest/metrics.go | 11 +-
server/rest/server.go | 48 -
server/rest/server_mux.go | 45 +-
server/rpc/server.go | 10 +-
server/server.go | 91 +-
server/service/dependency_test.go | 4 +-
.../event/{event.go => domain_event_handler.go} | 27 +-
server/service/event/event.go | 1 +
server/service/event/instance_event_handler.go | 14 +-
server/service/event/rule_event_handler.go | 4 +-
server/service/event/service_event_handler.go | 17 +
server/service/event/tag_event_handler.go | 4 +-
server/service/instance_test.go | 7 +-
server/service/metrics/metrics.go | 67 +
server/service/notification/common.go | 7 +-
.../service/notification/notification_service.go | 2 +-
server/service/notification/stream.go | 6 +-
server/service/notification/websocket.go | 99 +-
server/service/notification/websocket_test.go | 21 +-
server/service/rule_test.go | 27 +-
server/service/service_suite_test.go | 10 +-
server/service/tag_test.go | 3 +-
server/service/util/dependency_query.go | 4 +-
server/service/util/domain_util.go | 24 +-
server/service/util/domain_util_test.go | 4 +-
server/service/watch.go | 4 +-
server/{rpc/server.go => version.go} | 63 +-
173 files changed, 6662 insertions(+), 2601 deletions(-)
diff --git a/.gitignore b/.gitignore
index 84fb882..8bb0528 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,8 @@
bin/
output
**/*.coverprofile
+**/coverage.out
+**/coverage.txt
service-center.iml
.idea/
diff --git a/etc/conf/app.conf b/etc/conf/app.conf
index 4b49680..16fe484 100644
--- a/etc/conf/app.conf
+++ b/etc/conf/app.conf
@@ -60,17 +60,23 @@ registry_plugin = etcd
# manager_cluster = "127.0.0.1:2379"
manager_cluster = "127.0.0.1:2379"
-#heartbeat that sync synchronizes client's endpoints with the known endpoints from the etcd membership,unit is second.
-#<=0, use default 30s
+# heartbeat that sync synchronizes client's endpoints with the known endpoints from
+# the etcd membership, unit is second and value must greater then 1s, it is set
+# default 30s if value less then 0
auto_sync_interval = 30s
+# bootstrap time out of registry
+connect_timeout = 10s
+
+# request registry time out
registry_timeout = 30s
# indicate how many revision you want to keep in etcd
compact_index_delta = 100
compact_interval = 12h
-# registry cache
+# registry cache, if this option value set 0, service center can run
+# in lower memory but no longer push the events to client.
enable_cache = 1
# pluggable cipher
@@ -112,7 +118,7 @@ ssl_mode = 0
ssl_verify_client = 1
# minimal tls protocol, [TLSv1.0, TLSv1.1, TLSv1.2]
ssl_protocols = TLSv1.2
-ssl_ciphers = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256
+ssl_ciphers = TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256
###################################################################
# log options
diff --git a/examples/service_center/ssl/cert_pwd b/examples/service_center/ssl/cert_pwd
new file mode 100644
index 0000000..0a783b7
--- /dev/null
+++ b/examples/service_center/ssl/cert_pwd
@@ -0,0 +1 @@
+Changeme_123
\ No newline at end of file
diff --git a/examples/service_center/ssl/server.cer b/examples/service_center/ssl/server.cer
new file mode 100644
index 0000000..c29eb6a
--- /dev/null
+++ b/examples/service_center/ssl/server.cer
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICATCCAWoCCQDmvlmfua/ThTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB
+VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMB4XDTE3MTIwNTA5MzA0NloXDTE4MTIwNTA5MzA0NlowRTELMAkG
+A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtu5H
+L8mlCL6n+BrQ71eJgJJJ427/DgovzHBqLTYuk/It987wNJFmTMgdWRXHujwe4bFt
+G78d7OJteXcR7a68sIxWrytWeAwG88M62duS+DCUke1YuQ6hrfIADvE2ZgYEuVxz
+5UxOTYYIjtSxCGKDuxmlvkJgO6lE0zIhtFxz1WcCAwEAATANBgkqhkiG9w0BAQsF
+AAOBgQCq89sMPmhVS5+Mh+FvnNC9qOnsnqWhyAEc5XEmqtCTAe1XpO3CvPH7DdHz
+Ss0FVqpBRqmxUR0sQo6t/S0kW7uwDgjm7nIy67wtTLOLclYW2Yw+d3ApwBVMhVBp
+yhDpV90YZF7QM9uhdsEgLpbTqs4hvPB1pUWH6oXdtjnEkp6lFQ==
+-----END CERTIFICATE-----
diff --git a/examples/service_center/ssl/server_key.pem b/examples/service_center/ssl/server_key.pem
new file mode 100644
index 0000000..c0b907e
--- /dev/null
+++ b/examples/service_center/ssl/server_key.pem
@@ -0,0 +1,18 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,22C64A026937643A490027AC7931D19A
+
+FdV2dDDn5l767Ulha9IMxiwvyMu6BziFCjXbfsHB1aHdBfuFWV8uJ5lEYiWPWdj3
+QIeK79QH8i6N0n2f1VfXtW7RJKS+6Gg9m1dttxGXY/6sEIkFJRPiWrNrzeHaXAoI
+38CBZli2nvtZMLo8oBj/iuQ0qlkh00Mm2RW1SgJx2I6FJZLS8xb9kKUhPL/SlBYd
+EboWXpKtubg5DhvQd8MKIaTJDf3L1Iqc7OMnLs64ONvfylYy39uv8yGsimHNItQh
+ylHjUhmqOjCwnogO1Nh2wsjQCODRPEJzpu2fJ1lb2+xqwbTg3ygVwzLoK2ScXND4
+DIo8YOa9jBCR9/Yg1IzqOIUD+UzQWhBqDejMHVXAGQb5e2AldLdFnGwx1Yz4FCIl
+nULP8lcMDeYRK0sS4N5/I4nqfvlVPyj96Nj4F3D68Q8oQXl1rTSbKXmWILxIIlHm
+tBf+NA16p9A9TegHr/qn3L3NRCxyY7gLwL+cNG2uZ9NqmxnSmWhL9UQgWYPeGr8Z
+Z9nqqshfzIMoBjZ4QP1pifKhEvb0w2MpjKtiAR3hmwn8SJDp7CPTlb7nm5e5fjZb
+nkzsTXYaJiYYiuEjiIsxJY/6ptWeYq9kqTT/3Hmy0MdkcqeDbcLwqo6jbAJxcPFf
+C0SCJ+woIZJeHpZZjmH/qsZUKq2UEDsLqGruNMDzxarmme67lwPIDG2pZ90EIcNx
+BR0ZU4owv9N+dO2sFsMNHae9X8mHWynUJ2V3ISxshvS3WJmq+YkeYTjYljeIZ28x
++UBhUrmikzx/CrIFd9irnkVhPIqJ+uUZEiMNEnT7VxCpHZHDU+ujweChUzaLkh0x
+-----END RSA PRIVATE KEY-----
diff --git a/examples/service_center/ssl/trust.cer b/examples/service_center/ssl/trust.cer
new file mode 100644
index 0000000..8fb3139
--- /dev/null
+++ b/examples/service_center/ssl/trust.cer
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICATCCAWoCCQCu7pAj81WabjANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB
+VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMB4XDTE3MTIwNTA5MTMzNVoXDTE4MTIwNTA5MTMzNVowRTELMAkG
+A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyDpT
+In6x3H0HEGOXzJMByOnvzD4rL0B4wyE9K2Nng0Ev0pS0dlPQK67fZJ6e2KDcA72d
+dSps61YQ6tWnBbssCZat0qI2g3Kh4wKgEoCv/0Wm9J+c9gHO9VXyRd91FkJNFDB4
+Lsh4EF4kMVsdLfvP98LkQQAfjg621Yqa1bEu5RUCAwEAATANBgkqhkiG9w0BAQsF
+AAOBgQCbURtlhZMNUN8W2EQJVqgEbZmtNriI1VpKvfU4b8d05PwaoL3qV8tx6p5/
+2p/+diRH8XWkPMm0Ix+c7752ebWSVb8WoQL40ZBd4PIuy6RlS7/45VeMUk7LvxBG
+iPXnB72OzQmBiPhVNiINVumQWJ62NPlbYaJsG/WsZdaWYMDeww==
+-----END CERTIFICATE-----
diff --git a/frontend/main.go b/frontend/main.go
index 237b9ff..c460299 100644
--- a/frontend/main.go
+++ b/frontend/main.go
@@ -23,6 +23,7 @@ import (
"github.com/astaxie/beego"
"net"
"net/url"
+ "strconv"
)
type Config struct {
@@ -42,8 +43,8 @@ func main() {
flag.Parse()
cfg := Config{}
- cfg.scAddr = fmt.Sprintf("http://%s/", net.JoinHostPort(url.PathEscape(scIp), fmt.Sprint(scPort)))
- cfg.frontendAddr = net.JoinHostPort(frontendIp, fmt.Sprint(*port))
+ cfg.scAddr = fmt.Sprintf("http://%s/", net.JoinHostPort(url.PathEscape(scIp), strconv.Itoa(scPort)))
+ cfg.frontendAddr = net.JoinHostPort(frontendIp, strconv.Itoa(*port))
// run frontend web server
Serve(cfg)
diff --git a/pkg/etcdsync/mutex_test.go b/integration/admin_test.go
similarity index 55%
copy from pkg/etcdsync/mutex_test.go
copy to integration/admin_test.go
index 23a333b..a8cb888 100644
--- a/pkg/etcdsync/mutex_test.go
+++ b/integration/admin_test.go
@@ -14,36 +14,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package etcdsync_test
+package integrationtest_test
import (
- . "github.com/apache/incubator-servicecomb-service-center/pkg/etcdsync"
-
- "fmt"
+ . "github.com/apache/incubator-servicecomb-service-center/integration"
. "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ "github.com/widuu/gojson"
+ "io/ioutil"
+ "net/http"
)
-var _ = Describe("Mutex", func() {
- Context("normal", func() {
- It("TestLockTimeout", func() {
- m1 := NewLockFactory("key1", 10)
- m2 := NewLockFactory("key1", 2)
- m1.NewDLock(true)
- fmt.Println("UT===================m1 locked")
- ch := make(chan bool)
- go func() {
- l, _ := m2.NewDLock(true)
- fmt.Println("UT===================m2 locked")
- l.Unlock()
- ch <- true
- }()
- <-ch
- fmt.Println("lock m1 timeout")
- m3 := NewLockFactory("key1", 2)
- l, _ := m3.NewDLock(true)
- fmt.Println("UT===================m3 locked")
- l.Unlock()
-
- })
+var _ = Describe("Admin Api Test", func() {
+ It("dump", func() {
+ req, _ := http.NewRequest(GET, SCURL+DUMP, nil)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, err := scclient.Do(req)
+ respbody, _ := ioutil.ReadAll(resp.Body)
+ _, d := gojson.Json(string(respbody)).Getpath("cache", "services").ToArray()
+ Expect(err).To(BeNil())
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+ Expect(len(d)).ToNot(Equal(0))
+ defer resp.Body.Close()
})
})
diff --git a/integration/apis.go b/integration/apis.go
index d4ee813..ef65212 100644
--- a/integration/apis.go
+++ b/integration/apis.go
@@ -66,6 +66,9 @@ var UPDATETAG = "/v4/default/registry/microservices/:serviceId/tags/:key"
var GETTAGS = "/v4/default/registry/microservices/:serviceId/tags"
var DELETETAG = "/v4/default/registry/microservices/:serviceId/tags/:key"
+//Admin API's
+var DUMP = "/v4/default/admin/dump"
+
// HTTP METHODS
var GET = "GET"
var POST = "POST"
diff --git a/integration/health-metrics-grafana.json b/integration/health-metrics-grafana.json
index 280aec3..fdc80d2 100644
--- a/integration/health-metrics-grafana.json
+++ b/integration/health-metrics-grafana.json
@@ -33,6 +33,12 @@
},
{
"type": "panel",
+ "id": "grafana-piechart-panel",
+ "name": "Pie Chart",
+ "version": "1.3.3"
+ },
+ {
+ "type": "panel",
"id": "graph",
"name": "Graph",
"version": "5.0.0"
@@ -84,127 +90,30 @@
],
"panels": [
{
- "aliasColors": {},
- "bars": false,
- "dashLength": 10,
- "dashes": false,
- "datasource": "${DS_LOCAL}",
- "fill": 1,
- "gridPos": {
- "h": 6,
- "w": 8,
- "x": 0,
- "y": 0
- },
- "height": "",
- "id": 1,
- "legend": {
- "alignAsTable": true,
- "avg": true,
- "current": true,
- "max": false,
- "min": false,
- "show": true,
- "sort": null,
- "sortDesc": null,
- "total": false,
- "values": true
- },
- "lines": true,
- "linewidth": 1,
- "links": [],
- "minSpan": 4,
- "nullPointMode": "null",
- "percentage": false,
- "pointradius": 5,
- "points": false,
- "renderer": "flot",
- "seriesOverrides": [],
- "spaceLength": 10,
- "stack": false,
- "steppedLine": false,
- "targets": [
- {
- "expr": "max(max_over_time(service_center_http_request_durations_microseconds{job=\"service-center\",method=\"GET\"}[1m]))",
- "format": "time_series",
- "instant": false,
- "intervalFactor": 2,
- "legendFormat": "read",
- "refId": "A"
- },
- {
- "expr": "max(max_over_time(service_center_http_request_durations_microseconds{job=\"service-center\",method!=\"GET\"}[1m]))",
- "format": "time_series",
- "intervalFactor": 2,
- "legendFormat": "write",
- "refId": "B"
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeShift": null,
- "title": "I/O Latency",
- "tooltip": {
- "shared": true,
- "sort": 0,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "µs",
- "label": null,
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- },
- {
- "format": "short",
- "label": null,
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- }
- ],
- "yaxis": {
- "align": false,
- "alignLevel": null
- }
- },
- {
"cacheTimeout": null,
"colorBackground": false,
- "colorValue": true,
+ "colorValue": false,
"colors": [
- "#d44a3a",
+ "#299c46",
"rgba(237, 129, 40, 0.89)",
- "#299c46"
+ "#d44a3a"
],
"datasource": "${DS_LOCAL}",
- "format": "percentunit",
+ "format": "none",
"gauge": {
- "maxValue": 1,
+ "maxValue": 100,
"minValue": 0,
- "show": true,
+ "show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"gridPos": {
- "h": 6,
- "w": 4,
- "x": 8,
+ "h": 3,
+ "w": 2,
+ "x": 0,
"y": 0
},
- "id": 12,
+ "id": 27,
"interval": null,
"links": [],
"mappingType": 1,
@@ -237,20 +146,20 @@
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": true,
"lineColor": "rgb(31, 120, 193)",
- "show": true
+ "show": false
},
"tableColumn": "",
"targets": [
{
- "expr": "sum(service_center_http_success_total{job=\"service-center\"})/sum(service_center_http_request_total{job=\"service-center\"})",
+ "expr": "sum(service_center_db_sc_total{job=\"service-center\"})",
"format": "time_series",
+ "instant": false,
"intervalFactor": 2,
"refId": "A"
}
],
- "thresholds": ".5,.8",
- "title": "Global Success Rate",
- "transparent": false,
+ "thresholds": "",
+ "title": "ServiceCenters",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
@@ -281,12 +190,12 @@
"thresholdMarkers": true
},
"gridPos": {
- "h": 6,
- "w": 4,
- "x": 12,
+ "h": 3,
+ "w": 2,
+ "x": 2,
"y": 0
},
- "id": 13,
+ "id": 19,
"interval": null,
"links": [],
"mappingType": 1,
@@ -319,12 +228,12 @@
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": true,
"lineColor": "rgb(31, 120, 193)",
- "show": true
+ "show": false
},
"tableColumn": "",
"targets": [
{
- "expr": "sum(irate(service_center_http_request_total{job=\"service-center\"}[1m]))",
+ "expr": "max(service_center_db_backend_total{job=\"service-center\"})",
"format": "time_series",
"instant": false,
"intervalFactor": 2,
@@ -332,7 +241,7 @@
}
],
"thresholds": "",
- "title": "Global Request Volume",
+ "title": "Backends",
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
@@ -342,7 +251,7 @@
"value": "null"
}
],
- "valueName": "avg"
+ "valueName": "current"
},
{
"cacheTimeout": null,
@@ -354,7 +263,7 @@
"#d44a3a"
],
"datasource": "${DS_LOCAL}",
- "format": "rps",
+ "format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
@@ -363,12 +272,12 @@
"thresholdMarkers": true
},
"gridPos": {
- "h": 6,
- "w": 4,
- "x": 16,
+ "h": 3,
+ "w": 3,
+ "x": 4,
"y": 0
},
- "id": 10,
+ "id": 26,
"interval": null,
"links": [],
"mappingType": 1,
@@ -397,130 +306,1511 @@
"to": "null"
}
],
- "sparkline": {
- "fillColor": "rgba(31, 118, 189, 0.18)",
- "full": true,
- "lineColor": "rgb(31, 120, 193)",
- "show": true
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": true,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "max(service_center_db_domain_total{job=\"service-center\"})",
+ "format": "time_series",
+ "instant": false,
+ "intervalFactor": 2,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "Domain Volume",
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "${DS_LOCAL}",
+ "fill": 1,
+ "gridPos": {
+ "h": 5,
+ "w": 8,
+ "x": 7,
+ "y": 0
+ },
+ "height": "",
+ "id": 22,
+ "legend": {
+ "alignAsTable": true,
+ "avg": true,
+ "current": true,
+ "max": true,
+ "min": true,
+ "rightSide": false,
+ "show": true,
+ "sortDesc": true,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "minSpan": 4,
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "max(service_center_db_service_total{job=\"service-center\"})",
+ "format": "time_series",
+ "instant": false,
+ "intervalFactor": 2,
+ "legendFormat": "instances",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Microservices",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "locale",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "breakPoint": "50%",
+ "cacheTimeout": null,
+ "combine": {
+ "label": "Others",
+ "threshold": 0
+ },
+ "datasource": "${DS_LOCAL}",
+ "decimals": null,
+ "fontSize": "80%",
+ "format": "short",
+ "gridPos": {
+ "h": 5,
+ "w": 9,
+ "x": 15,
+ "y": 0
+ },
+ "id": 25,
+ "interval": null,
+ "legend": {
+ "header": "",
+ "percentage": true,
+ "percentageDecimals": 1,
+ "show": true,
+ "sideWidth": null,
+ "sort": "current",
+ "sortDesc": true,
+ "values": true
+ },
+ "legendType": "Right side",
+ "links": [],
+ "maxDataPoints": 3,
+ "nullPointMode": "connected",
+ "pieType": "pie",
+ "strokeWidth": 1,
+ "targets": [
+ {
+ "expr": "max(service_center_db_service_total{job=\"service-center\"}) by (framework)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{framework}}",
+ "refId": "A"
+ }
+ ],
+ "title": "Frameworks",
+ "type": "grafana-piechart-panel",
+ "valueName": "current"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "${DS_LOCAL}",
+ "format": "none",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 3,
+ "w": 3,
+ "x": 4,
+ "y": 3
+ },
+ "id": 20,
+ "interval": null,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "minSpan": 4,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": true,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "max(sum(service_center_db_service_total{job=\"service-center\"}) by (instance))",
+ "format": "time_series",
+ "instant": false,
+ "intervalFactor": 2,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "Microservice Volume",
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "${DS_LOCAL}",
+ "fill": 1,
+ "gridPos": {
+ "h": 5,
+ "w": 8,
+ "x": 7,
+ "y": 5
+ },
+ "height": "",
+ "id": 29,
+ "legend": {
+ "alignAsTable": true,
+ "avg": true,
+ "current": true,
+ "hideEmpty": false,
+ "hideZero": false,
+ "max": true,
+ "min": true,
+ "rightSide": false,
+ "show": true,
+ "sortDesc": true,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "minSpan": 4,
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "max(service_center_db_instance_total{job=\"service-center\"})",
+ "format": "time_series",
+ "instant": false,
+ "intervalFactor": 2,
+ "legendFormat": "instances",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Instances",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "locale",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "breakPoint": "50%",
+ "cacheTimeout": null,
+ "combine": {
+ "label": "Others",
+ "threshold": 0
+ },
+ "datasource": "${DS_LOCAL}",
+ "decimals": null,
+ "fontSize": "80%",
+ "format": "short",
+ "gridPos": {
+ "h": 5,
+ "w": 3,
+ "x": 15,
+ "y": 5
+ },
+ "id": 31,
+ "interval": null,
+ "legend": {
+ "header": "",
+ "percentage": true,
+ "percentageDecimals": 1,
+ "show": false,
+ "sideWidth": null,
+ "sort": "current",
+ "sortDesc": true,
+ "values": false
+ },
+ "legendType": "On graph",
+ "links": [],
+ "maxDataPoints": 3,
+ "nullPointMode": "connected",
+ "pieType": "pie",
+ "strokeWidth": 1,
+ "targets": [
+ {
+ "expr": "max(service_center_db_service_total{job=\"service-center\", framework=\"servicecomb-java-chassis\"}) by (frameworkVersion)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{frameworkVersion}}",
+ "refId": "A"
+ }
+ ],
+ "title": "Java Chassis Versions",
+ "type": "grafana-piechart-panel",
+ "valueName": "current"
+ },
+ {
+ "aliasColors": {},
+ "breakPoint": "50%",
+ "cacheTimeout": null,
+ "combine": {
+ "label": "Others",
+ "threshold": 0
+ },
+ "datasource": "${DS_LOCAL}",
+ "decimals": null,
+ "fontSize": "80%",
+ "format": "short",
+ "gridPos": {
+ "h": 5,
+ "w": 3,
+ "x": 18,
+ "y": 5
+ },
+ "id": 32,
+ "interval": null,
+ "legend": {
+ "header": "",
+ "percentage": true,
+ "percentageDecimals": 1,
+ "show": false,
+ "sideWidth": null,
+ "sort": "current",
+ "sortDesc": true,
+ "values": false
+ },
+ "legendType": "On graph",
+ "links": [],
+ "maxDataPoints": 3,
+ "nullPointMode": "connected",
+ "pieType": "pie",
+ "strokeWidth": 1,
+ "targets": [
+ {
+ "expr": "max(service_center_db_service_total{job=\"service-center\", framework=\"Go-Chassis\"}) by (frameworkVersion)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{frameworkVersion}}",
+ "refId": "A"
+ }
+ ],
+ "title": "Go Chassis Versions",
+ "type": "grafana-piechart-panel",
+ "valueName": "current"
+ },
+ {
+ "aliasColors": {},
+ "breakPoint": "50%",
+ "cacheTimeout": null,
+ "combine": {
+ "label": "Others",
+ "threshold": 0
+ },
+ "datasource": "${DS_LOCAL}",
+ "decimals": null,
+ "fontSize": "80%",
+ "format": "short",
+ "gridPos": {
+ "h": 5,
+ "w": 3,
+ "x": 21,
+ "y": 5
+ },
+ "id": 33,
+ "interval": null,
+ "legend": {
+ "header": "",
+ "percentage": true,
+ "percentageDecimals": 1,
+ "show": false,
+ "sideWidth": null,
+ "sort": "current",
+ "sortDesc": true,
+ "values": false
+ },
+ "legendType": "On graph",
+ "links": [],
+ "maxDataPoints": 3,
+ "nullPointMode": "connected",
+ "pieType": "pie",
+ "strokeWidth": 1,
+ "targets": [
+ {
+ "expr": "max(service_center_db_service_total{job=\"service-center\", framework=\"Mesher\"}) by (frameworkVersion)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{frameworkVersion}}",
+ "refId": "A"
+ }
+ ],
+ "title": "Mesher Versions",
+ "type": "grafana-piechart-panel",
+ "valueName": "current"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "${DS_LOCAL}",
+ "format": "none",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 3,
+ "w": 3,
+ "x": 4,
+ "y": 6
+ },
+ "id": 21,
+ "interval": null,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "minSpan": 4,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": true,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "Value",
+ "targets": [
+ {
+ "expr": "max(service_center_db_instance_total{job=\"service-center\"})",
+ "format": "time_series",
+ "instant": false,
+ "intervalFactor": 2,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "Instance Volume",
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ },
+ {
+ "content": "<div class=\"text-center dashboard-header\">\n <span>PERFORMANCE</span>\n</div>\n",
+ "gridPos": {
+ "h": 3,
+ "w": 24,
+ "x": 0,
+ "y": 10
+ },
+ "height": "1px",
+ "id": 3,
+ "links": [],
+ "mode": "html",
+ "repeat": null,
+ "title": "",
+ "transparent": true,
+ "type": "text"
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "${DS_LOCAL}",
+ "fill": 1,
+ "gridPos": {
+ "h": 6,
+ "w": 8,
+ "x": 0,
+ "y": 13
+ },
+ "height": "",
+ "id": 1,
+ "legend": {
+ "alignAsTable": true,
+ "avg": true,
+ "current": true,
+ "max": true,
+ "min": true,
+ "show": true,
+ "sort": null,
+ "sortDesc": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "minSpan": 4,
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(service_center_http_request_total{job=\"service-center\"}[1m]))",
+ "format": "time_series",
+ "instant": false,
+ "intervalFactor": 2,
+ "legendFormat": "tps",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "TPS",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "${DS_LOCAL}",
+ "format": "none",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 6,
+ "w": 4,
+ "x": 8,
+ "y": 13
+ },
+ "id": 13,
+ "interval": null,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "minSpan": 4,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": true,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": true
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "sum(irate(service_center_http_request_total{job=\"service-center\"}[1m]))",
+ "format": "time_series",
+ "instant": false,
+ "intervalFactor": 2,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "Global Request Volume",
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": true,
+ "colors": [
+ "#d44a3a",
+ "rgba(237, 129, 40, 0.89)",
+ "#299c46"
+ ],
+ "datasource": "${DS_LOCAL}",
+ "format": "percentunit",
+ "gauge": {
+ "maxValue": 1,
+ "minValue": 0,
+ "show": true,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 6,
+ "w": 4,
+ "x": 12,
+ "y": 13
+ },
+ "id": 12,
+ "interval": null,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "minSpan": 4,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": true,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": true
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "sum(service_center_http_success_total{job=\"service-center\"})/sum(service_center_http_request_total{job=\"service-center\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "refId": "A"
+ }
+ ],
+ "thresholds": ".5,.8",
+ "title": "Global Success Rate",
+ "transparent": false,
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "${DS_LOCAL}",
+ "format": "ops",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 6,
+ "w": 4,
+ "x": 16,
+ "y": 13
+ },
+ "id": 10,
+ "interval": null,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "minSpan": 4,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": true,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": true
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "sum(irate(service_center_http_request_total{job=\"service-center\",code=~\"4.+\"}[1m]))",
+ "format": "time_series",
+ "instant": false,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "4XX Errors",
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "avg"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "${DS_LOCAL}",
+ "format": "ops",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 6,
+ "w": 4,
+ "x": 20,
+ "y": 13
+ },
+ "id": 11,
+ "interval": null,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "minSpan": 4,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": true,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": true
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "sum(irate(service_center_http_request_total{job=\"service-center\",code=~\"5.+\"}[1m]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "5XX Errors",
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "avg"
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "${DS_LOCAL}",
+ "fill": 1,
+ "gridPos": {
+ "h": 6,
+ "w": 8,
+ "x": 0,
+ "y": 19
+ },
+ "height": "",
+ "id": 28,
+ "legend": {
+ "alignAsTable": true,
+ "avg": true,
+ "current": true,
+ "max": true,
+ "min": true,
+ "show": true,
+ "sort": null,
+ "sortDesc": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "minSpan": 4,
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(service_center_http_success_total{job=\"service-center\"})/sum(service_center_http_request_total{job=\"service-center\"})",
+ "format": "time_series",
+ "instant": false,
+ "intervalFactor": 2,
+ "legendFormat": "rate",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Success Rate",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "content": "<div class=\"text-center dashboard-header\">\n <span>INSTANCE METRICS</span>\n</div>\n",
+ "gridPos": {
+ "h": 3,
+ "w": 24,
+ "x": 0,
+ "y": 25
+ },
+ "height": "1px",
+ "id": 30,
+ "links": [],
+ "mode": "html",
+ "title": "",
+ "transparent": true,
+ "type": "text"
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "${DS_LOCAL}",
+ "fill": 1,
+ "gridPos": {
+ "h": 6,
+ "w": 6,
+ "x": 0,
+ "y": 28
+ },
+ "height": "",
+ "id": 18,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sort": "avg",
+ "sortDesc": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "minSpan": 4,
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(service_center_http_request_total{job=\"service-center\"}) by (method,api,instance)",
+ "format": "time_series",
+ "instant": false,
+ "intervalFactor": 2,
+ "legendFormat": "{{instance}}> {{method}} {{api}}",
+ "refId": "A"
+ },
+ {
+ "expr": "sum(service_center_http_request_total{job=\"service-center\"})",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{instance}}> Total",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Request Total",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "transparent": false,
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "${DS_LOCAL}",
+ "fill": 1,
+ "gridPos": {
+ "h": 6,
+ "w": 6,
+ "x": 6,
+ "y": 28
+ },
+ "height": "",
+ "id": 17,
+ "legend": {
+ "alignAsTable": true,
+ "avg": true,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": true,
+ "min": true,
+ "show": false,
+ "sort": null,
+ "sortDesc": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "minSpan": 4,
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(service_center_http_request_total{job=\"service-center\"}[1m])) by (method,api,instance)",
+ "format": "time_series",
+ "instant": false,
+ "intervalFactor": 2,
+ "legendFormat": "{{instance}}> {{method}} {{api}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "TPS of APIs",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "${DS_LOCAL}",
+ "fill": 1,
+ "gridPos": {
+ "h": 6,
+ "w": 6,
+ "x": 12,
+ "y": 28
},
- "tableColumn": "",
+ "height": "",
+ "id": 15,
+ "legend": {
+ "alignAsTable": false,
+ "avg": true,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": true,
+ "min": true,
+ "rightSide": true,
+ "show": false,
+ "sort": "avg",
+ "sortDesc": true,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "minSpan": 4,
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
"targets": [
{
- "expr": "sum(irate(service_center_http_request_total{job=\"service-center\",code=~\"4.+\"}[1m]))",
+ "expr": "max(avg_over_time(service_center_http_request_durations_microseconds{job=\"service-center\",method=\"GET\"}[1m])) by (method,api,instance)",
"format": "time_series",
"instant": false,
"intervalFactor": 2,
- "legendFormat": "",
+ "legendFormat": "{{instance}}> {{method}} {{api}}",
"refId": "A"
}
],
- "thresholds": "",
- "title": "4XX Errors",
- "type": "singlestat",
- "valueFontSize": "80%",
- "valueMaps": [
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Read Latency",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "transparent": false,
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
{
- "op": "=",
- "text": "N/A",
- "value": "null"
+ "format": "µs",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
}
],
- "valueName": "avg"
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
},
{
- "cacheTimeout": null,
- "colorBackground": false,
- "colorValue": false,
- "colors": [
- "#299c46",
- "rgba(237, 129, 40, 0.89)",
- "#d44a3a"
- ],
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
"datasource": "${DS_LOCAL}",
- "format": "rps",
- "gauge": {
- "maxValue": 100,
- "minValue": 0,
- "show": false,
- "thresholdLabels": false,
- "thresholdMarkers": true
- },
+ "fill": 1,
"gridPos": {
"h": 6,
- "w": 4,
- "x": 20,
- "y": 0
+ "w": 6,
+ "x": 18,
+ "y": 28
},
- "id": 11,
- "interval": null,
+ "height": "",
+ "id": 16,
+ "legend": {
+ "alignAsTable": false,
+ "avg": true,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": true,
+ "min": true,
+ "rightSide": true,
+ "show": false,
+ "sort": "avg",
+ "sortDesc": true,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
"links": [],
- "mappingType": 1,
- "mappingTypes": [
- {
- "name": "value to text",
- "value": 1
- },
- {
- "name": "range to text",
- "value": 2
- }
- ],
- "maxDataPoints": 100,
"minSpan": 4,
- "nullPointMode": "connected",
- "nullText": null,
- "postfix": "",
- "postfixFontSize": "50%",
- "prefix": "",
- "prefixFontSize": "50%",
- "rangeMaps": [
- {
- "from": "null",
- "text": "N/A",
- "to": "null"
- }
- ],
- "sparkline": {
- "fillColor": "rgba(31, 118, 189, 0.18)",
- "full": true,
- "lineColor": "rgb(31, 120, 193)",
- "show": true
- },
- "tableColumn": "",
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
"targets": [
{
- "expr": "sum(irate(service_center_http_request_total{job=\"service-center\",code=~\"5.+\"}[1m]))",
+ "expr": "max(avg_over_time(service_center_http_request_durations_microseconds{job=\"service-center\",method!=\"GET\"}[1m])) by (method,api,instance)",
"format": "time_series",
+ "instant": false,
"intervalFactor": 2,
+ "legendFormat": "{{instance}}> {{method}} {{api}}",
"refId": "A"
}
],
- "thresholds": "",
- "title": "5XX Errors",
- "type": "singlestat",
- "valueFontSize": "80%",
- "valueMaps": [
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Write Latency",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "transparent": false,
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
{
- "op": "=",
- "text": "N/A",
- "value": "null"
+ "format": "µs",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
}
],
- "valueName": "avg"
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
},
{
- "content": "<div class=\"text-center dashboard-header\">\n <span>INSTANCE METRICS</span>\n</div>\n",
+ "content": "<div class=\"text-center dashboard-header\">\n <span>RESOURCES</span>\n</div>\n",
"gridPos": {
"h": 3,
"w": 24,
"x": 0,
- "y": 6
+ "y": 34
},
"height": "1px",
- "id": 3,
+ "id": 4,
"links": [],
"mode": "html",
- "repeat": null,
"title": "",
"transparent": true,
"type": "text"
@@ -536,7 +1826,7 @@
"h": 7,
"w": 8,
"x": 0,
- "y": 9
+ "y": 37
},
"height": "",
"id": 2,
@@ -570,7 +1860,7 @@
"format": "time_series",
"instant": false,
"intervalFactor": 2,
- "legendFormat": "goroutines_{{instance}}",
+ "legendFormat": "{{instance}}",
"refId": "A"
}
],
@@ -625,7 +1915,7 @@
"h": 7,
"w": 8,
"x": 8,
- "y": 9
+ "y": 37
},
"height": "",
"id": 9,
@@ -657,7 +1947,7 @@
"format": "time_series",
"instant": false,
"intervalFactor": 2,
- "legendFormat": "cpu_{{instance}}",
+ "legendFormat": "{{instance}}",
"refId": "A"
}
],
@@ -712,7 +2002,7 @@
"h": 7,
"w": 8,
"x": 16,
- "y": 9
+ "y": 37
},
"height": "",
"id": 8,
@@ -740,11 +2030,11 @@
"steppedLine": false,
"targets": [
{
- "expr": "max(max_over_time(go_gc_duration_seconds{job=\"service-center\"}[1m])) by (instance)",
+ "expr": "max(avg_over_time(go_gc_duration_seconds{job=\"service-center\"}[1m])) by (instance)",
"format": "time_series",
"instant": false,
"intervalFactor": 2,
- "legendFormat": "gc_{{instance}}",
+ "legendFormat": "{{instance}}",
"refId": "A"
}
],
@@ -789,22 +2079,6 @@
}
},
{
- "content": "<div class=\"text-center dashboard-header\">\n <span>RESOURCES</span>\n</div>\n",
- "gridPos": {
- "h": 3,
- "w": 24,
- "x": 0,
- "y": 16
- },
- "height": "1px",
- "id": 4,
- "links": [],
- "mode": "html",
- "title": "",
- "transparent": true,
- "type": "text"
- },
- {
"aliasColors": {},
"bars": false,
"dashLength": 10,
@@ -815,7 +2089,7 @@
"h": 7,
"w": 8,
"x": 0,
- "y": 19
+ "y": 44
},
"id": 5,
"legend": {
@@ -845,7 +2119,7 @@
"expr": "go_threads{job=\"service-center\"}",
"format": "time_series",
"intervalFactor": 2,
- "legendFormat": "threads_{{instance}}",
+ "legendFormat": "{{instance}}",
"refId": "A"
}
],
@@ -900,7 +2174,7 @@
"h": 7,
"w": 8,
"x": 8,
- "y": 19
+ "y": 44
},
"id": 6,
"legend": {
@@ -930,7 +2204,7 @@
"expr": "process_open_fds{job=\"service-center\"}",
"format": "time_series",
"intervalFactor": 2,
- "legendFormat": "fds_{{instance}}",
+ "legendFormat": "{{instance}}",
"refId": "A"
}
],
@@ -985,7 +2259,7 @@
"h": 7,
"w": 8,
"x": 16,
- "y": 19
+ "y": 44
},
"id": 14,
"legend": {
@@ -1012,24 +2286,10 @@
"steppedLine": false,
"targets": [
{
- "expr": "go_memstats_heap_inuse_bytes{job=\"service-center\"} + go_memstats_heap_idle_bytes{job=\"service-center\"}",
- "format": "time_series",
- "intervalFactor": 1,
- "legendFormat": "heap_{{instance}}",
- "refId": "B"
- },
- {
- "expr": "go_memstats_heap_inuse_bytes{job=\"service-center\"}",
- "format": "time_series",
- "intervalFactor": 1,
- "legendFormat": "inuse_{{instance}}",
- "refId": "C"
- },
- {
"expr": "process_resident_memory_bytes{job=\"service-center\"}",
"format": "time_series",
"intervalFactor": 1,
- "legendFormat": "all_{{instance}}",
+ "legendFormat": "{{instance}}",
"refId": "A"
}
],
@@ -1084,7 +2344,7 @@
"h": 7,
"w": 24,
"x": 0,
- "y": 26
+ "y": 51
},
"id": 7,
"legend": {
@@ -1117,14 +2377,14 @@
"expr": "sum(service_center_local_cache_size_bytes{job=\"service-center\"}) by (resource,instance)",
"format": "time_series",
"intervalFactor": 2,
- "legendFormat": "{{resource}}_{{instance}}",
+ "legendFormat": "{{instance}}> {{resource}}",
"refId": "A"
},
{
"expr": "sum(service_center_local_cache_size_bytes{job=\"service-center\"}) by (instance)",
"format": "time_series",
"intervalFactor": 2,
- "legendFormat": "ALL_{{instance}}",
+ "legendFormat": "{{instance}}> ALL",
"refId": "B"
}
],
@@ -1208,5 +2468,5 @@
"timezone": "",
"title": "ServiceCenter",
"uid": "Zg6NoHGiz",
- "version": 6
+ "version": 45
}
\ No newline at end of file
diff --git a/integration/instances_test.go b/integration/instances_test.go
index ec71f21..458c45d 100644
--- a/integration/instances_test.go
+++ b/integration/instances_test.go
@@ -249,7 +249,7 @@ var _ = Describe("MicroService Api Test", func() {
By("Discover MicroService Instance API", func() {
It("Find Micro-service Info by AppID", func() {
- req, _ := http.NewRequest(GET, SCURL+FINDINSTANCE+"?noCache=1&appId="+serviceAppId+"&serviceName="+serviceName+"&version="+serviceVersion, nil)
+ req, _ := http.NewRequest(GET, SCURL+FINDINSTANCE+"?appId="+serviceAppId+"&serviceName="+serviceName+"&version="+serviceVersion, nil)
req.Header.Set("X-Domain-Name", "default")
req.Header.Set("X-ConsumerId", serviceId)
resp, _ := scclient.Do(req)
@@ -330,7 +330,7 @@ var _ = Describe("MicroService Api Test", func() {
})
It("Find Micro-Service Instance with rev", func() {
- req, _ := http.NewRequest(GET, SCURL+FINDINSTANCE+"?noCache=1&appId="+serviceAppId+"&serviceName="+serviceName+"&version="+serviceVersion, nil)
+ req, _ := http.NewRequest(GET, SCURL+FINDINSTANCE+"?appId="+serviceAppId+"&serviceName="+serviceName+"&version="+serviceVersion, nil)
req.Header.Set("X-Domain-Name", "default")
req.Header.Set("X-ConsumerId", serviceId)
resp, _ := scclient.Do(req)
@@ -349,6 +349,7 @@ var _ = Describe("MicroService Api Test", func() {
Expect(rev).NotTo(BeEmpty())
})
})
+
By("Update Micro-Service Instance Information API's", func() {
It("Update Micro-Service Instance Properties", func() {
propertiesInstance := map[string]interface{}{
@@ -473,6 +474,7 @@ var _ = Describe("MicroService Api Test", func() {
}
})
})
+
By("Micro-Service Instance heartbeat API", func() {
It("Send HeartBeat for micro-service instance", func() {
url := strings.Replace(INSTANCEHEARTBEAT, ":serviceId", serviceId, 1)
diff --git a/integration/microservices_test.go b/integration/microservices_test.go
index 9544580..0361275 100644
--- a/integration/microservices_test.go
+++ b/integration/microservices_test.go
@@ -410,9 +410,21 @@ var _ = Describe("MicroService Api Test", func() {
// Validate the dependency creation
Expect(resp.StatusCode).To(Equal(http.StatusOK))
- <-time.After(time.Second)
+ // add new dependency
+ dependency["providers"] = []interface{}{consumer}
+ body, _ = json.Marshal(bodyParams)
+ bodyBuf = bytes.NewReader(body)
+ req, _ = http.NewRequest(POST, SCURL+CREATEDEPENDENCIES, bodyBuf)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, err = scclient.Do(req)
+ Expect(err).To(BeNil())
+ defer resp.Body.Close()
+
+ // Validate the dependency creation
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
//Get Provider by ConsumerID
+ <-time.After(time.Second)
url := strings.Replace(GETCONPRODEPENDENCY, ":consumerId", consumerServiceID, 1)
req, _ = http.NewRequest(GET, SCURL+url, nil)
req.Header.Set("X-Domain-Name", "default")
@@ -432,7 +444,6 @@ var _ = Describe("MicroService Api Test", func() {
Expect(foundMicroService).To(Equal(true))
//Get Consumer by ProviderID
-
url = strings.Replace(GETPROCONDEPENDENCY, ":providerId", serviceId, 1)
req, _ = http.NewRequest(GET, SCURL+url, nil)
req.Header.Set("X-Domain-Name", "default")
@@ -451,10 +462,30 @@ var _ = Describe("MicroService Api Test", func() {
}
Expect(foundMicroService).To(Equal(true))
- providersArray = []interface{}{consumer}
+ //Get new dependency by ConsumerID
+ url = strings.Replace(GETCONPRODEPENDENCY, ":consumerId", consumerServiceID, 1)
+ req, _ = http.NewRequest(GET, SCURL+url, nil)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, _ = scclient.Do(req)
+ respbody, _ = ioutil.ReadAll(resp.Body)
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+ servicesStruct = map[string][]map[string]interface{}{}
+
+ json.Unmarshal(respbody, &servicesStruct)
+ foundMicroService = false
+ for _, services := range servicesStruct["providers"] {
+ if services["serviceName"] == consumerAppName {
+ foundMicroService = true
+ break
+ }
+ }
+ Expect(foundMicroService).To(Equal(true))
+
+ // override the dependency
+ dependency["providers"] = []interface{}{}
body, _ = json.Marshal(bodyParams)
bodyBuf = bytes.NewReader(body)
- req, _ = http.NewRequest(POST, SCURL+CREATEDEPENDENCIES, bodyBuf)
+ req, _ = http.NewRequest(UPDATE, SCURL+CREATEDEPENDENCIES, bodyBuf)
req.Header.Set("X-Domain-Name", "default")
resp, err = scclient.Do(req)
Expect(err).To(BeNil())
@@ -463,7 +494,8 @@ var _ = Describe("MicroService Api Test", func() {
// Validate the dependency creation
Expect(resp.StatusCode).To(Equal(http.StatusOK))
- //Get Provider by ConsumerID
+ //Get Provider by ConsumerID again
+ <-time.After(time.Second)
url = strings.Replace(GETCONPRODEPENDENCY, ":consumerId", consumerServiceID, 1)
req, _ = http.NewRequest(GET, SCURL+url, nil)
req.Header.Set("X-Domain-Name", "default")
@@ -471,16 +503,8 @@ var _ = Describe("MicroService Api Test", func() {
respbody, _ = ioutil.ReadAll(resp.Body)
Expect(resp.StatusCode).To(Equal(http.StatusOK))
servicesStruct = map[string][]map[string]interface{}{}
-
json.Unmarshal(respbody, &servicesStruct)
- foundMicroService = false
- for _, services := range servicesStruct["providers"] {
- if services["serviceName"] == serviceName {
- foundMicroService = true
- break
- }
- }
- Expect(foundMicroService).To(Equal(true))
+ Expect(len(servicesStruct["providers"])).To(Equal(0))
//Delete Consumer and Provider
url = strings.Replace(UNREGISTERMICROSERVICE, ":serviceId", consumerServiceID, 1)
@@ -498,7 +522,6 @@ var _ = Describe("MicroService Api Test", func() {
})
It("Invalid scenario for GET Providers and Consumers", func() {
-
//Get Provider by ConsumerID
url := strings.Replace(GETCONPRODEPENDENCY, ":consumerId", "wrongID", 1)
req, _ := http.NewRequest(GET, SCURL+url, nil)
diff --git a/integration/rules_test.go b/integration/rules_test.go
index 206f039..13543c3 100644
--- a/integration/rules_test.go
+++ b/integration/rules_test.go
@@ -28,6 +28,7 @@ import (
"net/http"
"strconv"
"strings"
+ "time"
)
var _ = Describe("MicroService Api Test", func() {
@@ -185,8 +186,9 @@ var _ = Describe("MicroService Api Test", func() {
Expect(resp.StatusCode).To(Equal(http.StatusOK))
//Duplicate Request
+ <-time.After(time.Second)
bodyBuf = bytes.NewReader(body)
- req, _ = http.NewRequest(POST, SCURL+url+"?noCache=1", bodyBuf)
+ req, _ = http.NewRequest(POST, SCURL+url, bodyBuf)
req.Header.Set("X-Domain-Name", "default")
resp, err = scclient.Do(req)
Expect(err).To(BeNil())
@@ -224,8 +226,9 @@ var _ = Describe("MicroService Api Test", func() {
Expect(resp.StatusCode).To(Equal(http.StatusOK))
//Get Rules
+ <-time.After(time.Second)
url = strings.Replace(GETRULES, ":serviceId", serviceId, 1)
- req, _ = http.NewRequest(GET, SCURL+url+"?noCache=1", nil)
+ req, _ = http.NewRequest(GET, SCURL+url, nil)
req.Header.Set("X-Domain-Name", "default")
req.Header.Set("X-ConsumerId", serviceId)
resp, _ = scclient.Do(req)
@@ -295,6 +298,7 @@ var _ = Describe("MicroService Api Test", func() {
}
//Update Rules
+ <-time.After(time.Second)
updateParams := map[string]interface{}{
"ruleType": "WHITE",
"attribute": "tag_b",
@@ -305,7 +309,7 @@ var _ = Describe("MicroService Api Test", func() {
url = strings.Replace(url, ":rule_id", ruleID, 1)
body, _ = json.Marshal(updateParams)
bodyBuf = bytes.NewReader(body)
- req, _ = http.NewRequest(UPDATE, SCURL+url+"?noCache=1", bodyBuf)
+ req, _ = http.NewRequest(UPDATE, SCURL+url, bodyBuf)
req.Header.Set("X-Domain-Name", "default")
resp, err = scclient.Do(req)
Expect(err).To(BeNil())
@@ -314,8 +318,9 @@ var _ = Describe("MicroService Api Test", func() {
Expect(resp.StatusCode).To(Equal(http.StatusOK))
//Get Rules
+ <-time.After(time.Second)
url = strings.Replace(GETRULES, ":serviceId", serviceId, 1)
- req, _ = http.NewRequest(GET, SCURL+url+"?noCache=1", nil)
+ req, _ = http.NewRequest(GET, SCURL+url, nil)
req.Header.Set("X-Domain-Name", "default")
req.Header.Set("X-ConsumerId", serviceId)
resp, _ = scclient.Do(req)
@@ -362,6 +367,7 @@ var _ = Describe("MicroService Api Test", func() {
}
//Update Rules with invalid RuleType
+ <-time.After(time.Second)
updateParams := map[string]interface{}{
"ruleType": "UNKNOWN",
"attribute": "tag_b",
@@ -372,7 +378,7 @@ var _ = Describe("MicroService Api Test", func() {
url = strings.Replace(url, ":rule_id", ruleID, 1)
body, _ = json.Marshal(updateParams)
bodyBuf = bytes.NewReader(body)
- req, _ = http.NewRequest(UPDATE, SCURL+url+"?noCache=1", bodyBuf)
+ req, _ = http.NewRequest(UPDATE, SCURL+url, bodyBuf)
req.Header.Set("X-Domain-Name", "default")
resp, err = scclient.Do(req)
Expect(err).To(BeNil())
@@ -380,6 +386,7 @@ var _ = Describe("MicroService Api Test", func() {
Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))
//Update Rules with invalid pattern
+ <-time.After(time.Second)
updateParams = map[string]interface{}{
"ruleType": "WHITE",
"attribute": "tag_b",
@@ -390,7 +397,7 @@ var _ = Describe("MicroService Api Test", func() {
url = strings.Replace(url, ":rule_id", ruleID, 1)
body, _ = json.Marshal(updateParams)
bodyBuf = bytes.NewReader(body)
- req, _ = http.NewRequest(UPDATE, SCURL+url+"?noCache=1", bodyBuf)
+ req, _ = http.NewRequest(UPDATE, SCURL+url, bodyBuf)
req.Header.Set("X-Domain-Name", "default")
resp, err = scclient.Do(req)
Expect(err).To(BeNil())
@@ -398,6 +405,7 @@ var _ = Describe("MicroService Api Test", func() {
Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))
//Update Rules with invalid different ruleType
+ <-time.After(time.Second)
updateParams = map[string]interface{}{
"ruleType": "BLACK",
"attribute": "tag_b",
@@ -408,7 +416,7 @@ var _ = Describe("MicroService Api Test", func() {
url = strings.Replace(url, ":rule_id", ruleID, 1)
body, _ = json.Marshal(updateParams)
bodyBuf = bytes.NewReader(body)
- req, _ = http.NewRequest(UPDATE, SCURL+url+"?noCache=1", bodyBuf)
+ req, _ = http.NewRequest(UPDATE, SCURL+url, bodyBuf)
req.Header.Set("X-Domain-Name", "default")
resp, err = scclient.Do(req)
Expect(err).To(BeNil())
@@ -470,9 +478,10 @@ var _ = Describe("MicroService Api Test", func() {
}
//Delete the Rules
+ <-time.After(time.Second)
url = strings.Replace(DELETERULES, ":serviceId", serviceId, 1)
url = strings.Replace(url, ":rule_id", ruleID, 1)
- req, _ = http.NewRequest(DELETE, SCURL+url+"?noCache=1", nil)
+ req, _ = http.NewRequest(DELETE, SCURL+url, nil)
req.Header.Set("X-Domain-Name", "default")
resp, err = scclient.Do(req)
Expect(err).To(BeNil())
@@ -480,8 +489,9 @@ var _ = Describe("MicroService Api Test", func() {
Expect(resp.StatusCode).To(Equal(http.StatusOK))
//verify Delete
+ <-time.After(time.Second)
url = strings.Replace(GETTAGS, ":serviceId", serviceId, 1)
- req, _ = http.NewRequest(GET, SCURL+url+"?noCache=1", nil)
+ req, _ = http.NewRequest(GET, SCURL+url, nil)
req.Header.Set("X-Domain-Name", "default")
req.Header.Set("X-ConsumerId", serviceId)
resp, _ = scclient.Do(req)
diff --git a/integration/tags_test.go b/integration/tags_test.go
index 78b3a50..ba96a7c 100644
--- a/integration/tags_test.go
+++ b/integration/tags_test.go
@@ -159,8 +159,9 @@ var _ = Describe("MicroService Api Test", func() {
Expect(resp.StatusCode).To(Equal(http.StatusOK))
//Get Tags
+ <-time.After(time.Second)
url = strings.Replace(GETTAGS, ":serviceId", serviceId, 1)
- req, _ = http.NewRequest(GET, SCURL+url+"?noCache=1", nil)
+ req, _ = http.NewRequest(GET, SCURL+url, nil)
req.Header.Set("X-Domain-Name", "default")
req.Header.Set("X-ConsumerId", serviceId)
resp, _ = scclient.Do(req)
@@ -215,9 +216,10 @@ var _ = Describe("MicroService Api Test", func() {
Expect(resp.StatusCode).To(Equal(http.StatusOK))
//Update Tags
+ <-time.After(time.Second)
url = strings.Replace(UPDATETAG, ":serviceId", serviceId, 1)
url = strings.Replace(url, ":key", "testkey", 1)
- req, _ = http.NewRequest(UPDATE, SCURL+url+"?value=newValue&noCache=1", nil)
+ req, _ = http.NewRequest(UPDATE, SCURL+url+"?value=newValue", nil)
req.Header.Set("X-Domain-Name", "default")
resp, err = scclient.Do(req)
Expect(err).To(BeNil())
@@ -227,7 +229,7 @@ var _ = Describe("MicroService Api Test", func() {
//Verify the Tags
<-time.After(time.Second)
url = strings.Replace(GETTAGS, ":serviceId", serviceId, 1)
- req, _ = http.NewRequest(GET, SCURL+url+"?noCache=1", nil)
+ req, _ = http.NewRequest(GET, SCURL+url, nil)
req.Header.Set("X-Domain-Name", "default")
req.Header.Set("X-ConsumerId", serviceId)
resp, _ = scclient.Do(req)
@@ -266,9 +268,10 @@ var _ = Describe("MicroService Api Test", func() {
Expect(resp.StatusCode).To(Equal(http.StatusOK))
//Update Tags
+ <-time.After(time.Second)
url = strings.Replace(UPDATETAG, ":serviceId", serviceId, 1)
url = strings.Replace(url, ":key", "unknownkey", 1)
- req, _ = http.NewRequest(UPDATE, SCURL+url+"?value=newValue&noCache=1", nil)
+ req, _ = http.NewRequest(UPDATE, SCURL+url+"?value=newValue", nil)
req.Header.Set("X-Domain-Name", "default")
resp, err = scclient.Do(req)
Expect(err).To(BeNil())
@@ -311,9 +314,10 @@ var _ = Describe("MicroService Api Test", func() {
Expect(resp.StatusCode).To(Equal(http.StatusOK))
//Delete the tag
+ <-time.After(time.Second)
url = strings.Replace(DELETETAG, ":serviceId", serviceId, 1)
url = strings.Replace(url, ":key", "testkey", 1)
- req, _ = http.NewRequest(DELETE, SCURL+url+"?noCache=1", nil)
+ req, _ = http.NewRequest(DELETE, SCURL+url, nil)
req.Header.Set("X-Domain-Name", "default")
resp, err = scclient.Do(req)
Expect(err).To(BeNil())
@@ -323,7 +327,7 @@ var _ = Describe("MicroService Api Test", func() {
//verify Delete
<-time.After(time.Second)
url = strings.Replace(GETTAGS, ":serviceId", serviceId, 1)
- req, _ = http.NewRequest(GET, SCURL+url+"?noCache=1", nil)
+ req, _ = http.NewRequest(GET, SCURL+url, nil)
req.Header.Set("X-Domain-Name", "default")
req.Header.Set("X-ConsumerId", serviceId)
resp, _ = scclient.Do(req)
@@ -353,9 +357,10 @@ var _ = Describe("MicroService Api Test", func() {
Expect(resp.StatusCode).To(Equal(http.StatusOK))
//Delete the tag
+ <-time.After(time.Second)
url = strings.Replace(DELETETAG, ":serviceId", serviceId, 1)
url = strings.Replace(url, ":key", "unknowTag", 1)
- req, _ = http.NewRequest(DELETE, SCURL+url+"?noCache=1", nil)
+ req, _ = http.NewRequest(DELETE, SCURL+url, nil)
req.Header.Set("X-Domain-Name", "default")
resp, err = scclient.Do(req)
Expect(err).To(BeNil())
@@ -363,8 +368,9 @@ var _ = Describe("MicroService Api Test", func() {
Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))
//verify Non-deleted of exsiting tag
+ <-time.After(time.Second)
url = strings.Replace(GETTAGS, ":serviceId", serviceId, 1)
- req, _ = http.NewRequest(GET, SCURL+url+"?noCache=1", nil)
+ req, _ = http.NewRequest(GET, SCURL+url, nil)
req.Header.Set("X-Domain-Name", "default")
req.Header.Set("X-ConsumerId", serviceId)
resp, _ = scclient.Do(req)
diff --git a/main.go b/main.go
index 3d7ac97..efbcaac 100644
--- a/main.go
+++ b/main.go
@@ -16,20 +16,12 @@
*/
package main
-// plugins
+import _ "github.com/apache/incubator-servicecomb-service-center/server/init"
import _ "github.com/apache/incubator-servicecomb-service-center/server/bootstrap"
import (
- "github.com/apache/incubator-servicecomb-service-center/pkg/util"
"github.com/apache/incubator-servicecomb-service-center/server"
- "github.com/apache/incubator-servicecomb-service-center/server/core/backend"
)
func main() {
server.Run()
-
- util.GoCloseAndWait()
-
- backend.Registry().Close()
-
- util.Logger().Warn("service center exited", nil)
}
diff --git a/pkg/chain/callback_test.go b/pkg/chain/callback_test.go
new file mode 100644
index 0000000..db452a6
--- /dev/null
+++ b/pkg/chain/callback_test.go
@@ -0,0 +1,56 @@
+/*
+ * 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 chain
+
+import (
+ "errors"
+ "testing"
+)
+
+func TestCallback_Invoke(t *testing.T) {
+ cb := &Callback{Func: func(r Result) {
+ if r.Args[0].(bool) != r.OK {
+ t.Fatalf("TestCallback_Invoke failed")
+ }
+ if !r.OK && r.Err == nil {
+ t.Fatalf("TestCallback_Invoke failed")
+ }
+ }, Async: false}
+ cb.Success(true)
+ cb.Fail(errors.New("error"), false)
+ cb.Invoke(Result{OK: true, Args: []interface{}{true}})
+
+ ch := make(chan struct{})
+ cb = &Callback{Func: func(r Result) {
+ if r.Args[0].(bool) != r.OK {
+ t.Fatalf("TestCallback_Invoke failed")
+ }
+ if !r.OK && r.Err == nil {
+ t.Fatalf("TestCallback_Invoke failed")
+ }
+ ch <- struct{}{}
+ }, Async: true}
+ cb.Success(true)
+ cb.Fail(errors.New("error"), false)
+ cb.Invoke(Result{OK: true, Args: []interface{}{true}})
+ <-ch
+
+ cb = &Callback{}
+ cb.Success(true)
+ cb.Fail(errors.New("error"), false)
+ cb.Invoke(Result{OK: true, Args: []interface{}{true}})
+}
diff --git a/pkg/chain/chain_test.go b/pkg/chain/chain_test.go
index 1bec164..d053a81 100644
--- a/pkg/chain/chain_test.go
+++ b/pkg/chain/chain_test.go
@@ -14,11 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package chain_test
+package chain
import (
"context"
- "github.com/apache/incubator-servicecomb-service-center/pkg/chain"
+ "errors"
"github.com/apache/incubator-servicecomb-service-center/pkg/util"
"testing"
)
@@ -30,14 +30,14 @@ const (
func init() {
for i := 0; i < count; i++ {
- chain.RegisterHandler("_bench_handlers_", &handler{})
+ RegisterHandler("_bench_handlers_", &handler{})
}
}
type handler struct {
}
-func (h *handler) Handle(i *chain.Invocation) {
+func (h *handler) Handle(i *Invocation) {
i.Next()
}
@@ -50,9 +50,9 @@ func syncFunc(i int) {
func BenchmarkInvocationOption(b *testing.B) {
var (
- op chain.InvocationOp
- f = func(r chain.Result) {}
- opts = []chain.InvocationOption{chain.WithFunc(f), chain.WithAsyncFunc(f)}
+ op InvocationOp
+ f = func(r Result) {}
+ opts = []InvocationOption{WithFunc(f), WithAsyncFunc(f)}
)
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
@@ -68,14 +68,14 @@ func BenchmarkInvocationOption(b *testing.B) {
func BenchmarkChain(b *testing.B) {
var (
ctx = util.NewStringContext(context.Background())
- f = func(r chain.Result) {}
+ f = func(r Result) {}
)
b.N = times
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
- inv := chain.NewInvocation(ctx, chain.NewChain("_bench_chain_", chain.Handlers("_bench_handlers_")))
+ inv := NewInvocation(ctx, NewChain("_bench_chain_", Handlers("_bench_handlers_")))
inv.Invoke(f)
}
})
@@ -94,3 +94,135 @@ func BenchmarkSync(b *testing.B) {
b.ReportAllocs()
// 1000000 46.9 ns/op 0 B/op 0 allocs/op
}
+
+type mockHandler struct {
+}
+
+func (h *mockHandler) Handle(i *Invocation) {
+ x := i.Context().Value("x").(int)
+ switch x {
+ case 1:
+ i.Success(x)
+ case 2:
+ i.Fail(errors.New("error"), x)
+ case 3:
+ i.Next(WithFunc(func(r Result) {
+ i.WithContext("x", x*x)
+ }))
+ case 4:
+ i.Next(WithAsyncFunc(func(r Result) {
+ i.WithContext("x", x*x)
+ i.Context().Value("ch").(chan struct{}) <- struct{}{}
+ }))
+ case 5:
+ panic(errors.New("error"))
+ case 6:
+ i.Next(WithFunc(func(r Result) {
+ panic(errors.New("error"))
+ }))
+ case 7:
+ i.Next(WithAsyncFunc(func(r Result) {
+ panic(errors.New("error"))
+ }))
+ default:
+ i.WithContext("x", x-1)
+ i.Next()
+ }
+}
+
+func TestChain_Next(t *testing.T) {
+ h := &mockHandler{}
+ hs := Handlers("test")
+ hs = []Handler{h, h, h}
+
+ x := 0
+ ch := NewChain("test", hs)
+ if ch.Name() != "test" {
+ t.Fatalf("TestChain_Next")
+ }
+ i := NewInvocation(context.Background(), ch)
+ i.WithContext("x", x)
+ i.Invoke(func(r Result) {
+ if !r.OK || i.Context().Value("x").(int) != -len(hs) {
+ t.Fatalf("TestChain_Next")
+ }
+ })
+
+ x = 1
+ ch = NewChain("test", hs)
+ i = NewInvocation(context.Background(), ch)
+ i.WithContext("x", x)
+ i.Invoke(func(r Result) {
+ if !r.OK || r.Args[0].(int) != x {
+ t.Fatalf("TestChain_Next")
+ }
+ })
+
+ x = 2
+ ch = NewChain("test", hs)
+ i = NewInvocation(context.Background(), ch)
+ i.WithContext("x", x)
+ i.Invoke(func(r Result) {
+ if r.OK || r.Args[0].(int) != x {
+ t.Fatalf("TestChain_Next")
+ }
+ })
+
+ x = 3
+ ch = NewChain("test", hs)
+ i = NewInvocation(context.Background(), ch)
+ i.WithContext("x", x)
+ i.Invoke(func(r Result) {
+ if !r.OK || i.Context().Value("x").(int) != x {
+ t.Fatalf("TestChain_Next")
+ }
+ })
+ if i.Context().Value("x").(int) != x*x {
+ t.Fatalf("TestChain_Next")
+ }
+
+ x = 4
+ ch = NewChain("test", hs)
+ i = NewInvocation(context.Background(), ch)
+ i.WithContext("x", x)
+ i.WithContext("ch", make(chan struct{}))
+ i.Invoke(func(r Result) {
+ if !r.OK || i.Context().Value("x").(int) != x {
+ t.Fatalf("TestChain_Next")
+ }
+ })
+ <-i.Context().Value("ch").(chan struct{})
+ if i.Context().Value("x").(int) != x*x {
+ t.Fatalf("TestChain_Next")
+ }
+
+ x = 5
+ ch = NewChain("test", hs)
+ i = NewInvocation(context.Background(), ch)
+ i.WithContext("x", x)
+ i.Invoke(func(r Result) {
+ if r.OK || r.Err == nil {
+ t.Fatalf("TestChain_Next")
+ }
+ })
+
+ x = 6
+ ch = NewChain("test", hs)
+ i = NewInvocation(context.Background(), ch)
+ i.WithContext("x", x)
+ i.Invoke(func(r Result) {
+ if !r.OK || r.Err != nil {
+ t.Fatalf("TestChain_Next")
+ }
+ })
+
+ x = 7
+ ch = NewChain("test", hs)
+ i = NewInvocation(context.Background(), ch)
+ i.WithContext("x", x)
+ i.Invoke(func(r Result) {
+ if !r.OK || r.Err != nil {
+ t.Fatalf("TestChain_Next")
+ }
+ })
+}
diff --git a/pkg/chain/handler.go b/pkg/chain/handler.go
index 372e8c7..5efdab7 100644
--- a/pkg/chain/handler.go
+++ b/pkg/chain/handler.go
@@ -36,8 +36,8 @@ func RegisterHandler(catalog string, h Handler) {
handlers = append(handlers, h)
handlersMap[catalog] = handlers
- t := util.ReflectObject(h)
- util.Logger().Infof("register handler[%s] %s/%s", catalog, t.Type.PkgPath(), t.Type.Name())
+ t := util.Reflect(h)
+ util.Logger().Infof("register handler[%s] %s", catalog, t.Name())
}
func Handlers(catalog string) []Handler {
diff --git a/pkg/chain/invocation.go b/pkg/chain/invocation.go
index 5e5276c..bb024ca 100644
--- a/pkg/chain/invocation.go
+++ b/pkg/chain/invocation.go
@@ -55,6 +55,12 @@ func (i *Invocation) WithContext(key string, val interface{}) *Invocation {
return i
}
+// Next is the method to go next step in handler chain
+// WithFunc and WithAsyncFunc options can add customize callbacks in chain
+// and the callbacks seq like below
+// i.Success/Fail() -> CB1 ---> CB3 ----------> END goroutine 0
+// \-> CB2(async) \ goroutine 1
+// \-> CB4(async) goroutine 1 or 2
func (i *Invocation) Next(opts ...InvocationOption) {
var op InvocationOp
for _, opt := range opts {
@@ -75,11 +81,6 @@ func (i *Invocation) setCallback(f CallbackFunc, async bool) {
i.Async = async
return
}
-
- // the callbacks seq like below
- // i.Success() -> CB1 ---> CB3 ----------> END goroutine 0
- // \-> CB2(async) \ goroutine 1
- // \-> CB4(async) goroutine 1 or 2
cb := i.Func
i.Func = func(r Result) {
cb(r)
diff --git a/pkg/etcdsync/etcdsync_suite_test.go b/pkg/etcdsync/etcdsync_suite_test.go
index 7af14fa..c5ded54 100644
--- a/pkg/etcdsync/etcdsync_suite_test.go
+++ b/pkg/etcdsync/etcdsync_suite_test.go
@@ -14,22 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package etcdsync_test
+package etcdsync
import (
- _ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/registry/embededetcd"
+ "fmt"
_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/registry/etcd"
+ _ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/tracing/buildin"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
-)
-import (
- "fmt"
- "github.com/apache/incubator-servicecomb-service-center/pkg/etcdsync"
"testing"
)
func init() {
- etcdsync.IsDebug = true
+ IsDebug = true
}
func TestEtcdsync(t *testing.T) {
@@ -41,11 +38,11 @@ func BenchmarkLock(b *testing.B) {
var g = 0
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
- lock, _ := etcdsync.Lock("/test", true)
- defer lock.Unlock()
+ lock, _ := Lock("/test", true)
//do something
g += 1
fmt.Println(g)
+ lock.Unlock()
}
})
fmt.Println("Parallel:", b.N)
diff --git a/pkg/etcdsync/mutex.go b/pkg/etcdsync/mutex.go
index d1a35b9..cc7fc2d 100644
--- a/pkg/etcdsync/mutex.go
+++ b/pkg/etcdsync/mutex.go
@@ -50,10 +50,11 @@ var (
globalMap = make(map[string]*DLockFactory)
globalMux sync.Mutex
IsDebug bool
- hostname string = util.HostName()
- pid int = os.Getpid()
+ hostname = util.HostName()
+ pid = os.Getpid()
)
+// lock will not be release automatically if ttl = 0
func NewLockFactory(key string, ttl int64) *DLockFactory {
if len(key) == 0 {
return nil
@@ -81,86 +82,92 @@ func (m *DLockFactory) NewDLock(wait bool) (l *DLock, err error) {
for try := 1; try <= DEFAULT_RETRY_TIMES; try++ {
err = l.Lock(wait)
if err == nil {
- return l, nil
+ return
}
if !wait {
- l, err = nil, nil
break
}
-
- if try <= DEFAULT_RETRY_TIMES {
- util.Logger().Warnf(err, "Try to lock key %s again, id=%s", m.key, l.id)
- } else {
- util.Logger().Errorf(err, "Lock key %s failed, id=%s", m.key, l.id)
- }
}
+ // failed
+ util.Logger().Errorf(err, "Lock key %s failed, id=%s", m.key, l.id)
+ l = nil
+
if !IsDebug {
m.mutex.Unlock()
}
- return l, err
+ return
}
func (m *DLock) ID() string {
return m.id
}
-func (m *DLock) Lock(wait bool) error {
+func (m *DLock) Lock(wait bool) (err error) {
opts := []registry.PluginOpOption{
registry.WithStrKey(m.builder.key),
registry.WithStrValue(m.id)}
- for {
- util.Logger().Infof("Trying to create a lock: key=%s, id=%s", m.builder.key, m.id)
+ util.Logger().Infof("Trying to create a lock: key=%s, id=%s", m.builder.key, m.id)
- putOpts := opts
- if m.builder.ttl > 0 {
- leaseID, err := backend.Registry().LeaseGrant(m.builder.ctx, m.builder.ttl)
- if err != nil {
- return err
- }
- putOpts = append(opts, registry.WithLease(leaseID))
- }
- success, err := backend.Registry().PutNoOverride(m.builder.ctx, putOpts...)
- if err == nil && success {
- util.Logger().Infof("Create Lock OK, key=%s, id=%s", m.builder.key, m.id)
- return nil
+ var leaseID int64
+ putOpts := opts
+ if m.builder.ttl > 0 {
+ leaseID, err = backend.Registry().LeaseGrant(m.builder.ctx, m.builder.ttl)
+ if err != nil {
+ return err
}
+ putOpts = append(opts, registry.WithLease(leaseID))
+ }
+ success, err := backend.Registry().PutNoOverride(m.builder.ctx, putOpts...)
+ if err == nil && success {
+ util.Logger().Infof("Create Lock OK, key=%s, id=%s", m.builder.key, m.id)
+ return nil
+ }
- if !wait {
- return fmt.Errorf("Key %s is locked by id=%s", m.builder.key, m.id)
- }
+ if leaseID > 0 {
+ backend.Registry().LeaseRevoke(m.builder.ctx, leaseID)
+ }
+
+ if m.builder.ttl == 0 || !wait {
+ return fmt.Errorf("Key %s is locked by id=%s", m.builder.key, m.id)
+ }
- util.Logger().Warnf(err, "Key %s is locked, waiting for other node releases it, id=%s", m.builder.key, m.id)
-
- ctx, cancel := context.WithTimeout(m.builder.ctx, DEFAULT_LOCK_TTL*time.Second)
- util.Go(func(context.Context) {
- defer cancel()
- err := backend.Registry().Watch(ctx,
- registry.WithStrKey(m.builder.key),
- registry.WithWatchCallback(
- func(message string, evt *registry.PluginResponse) error {
- if evt != nil && evt.Action == registry.Delete {
- // break this for-loop, and try to create the node again.
- return fmt.Errorf("Lock released")
- }
- return nil
- }))
- if err != nil {
- util.Logger().Warnf(nil, "%s, key=%s, id=%s", err.Error(), m.builder.key, m.id)
- }
- })
- select {
- case <-ctx.Done():
- continue // 可以重新尝试获取锁
- case <-m.builder.ctx.Done():
- cancel()
- return m.builder.ctx.Err() // 机制错误,不应该超时的
+ util.Logger().Warnf(err, "Key %s is locked, waiting for other node releases it, id=%s", m.builder.key, m.id)
+
+ ctx, cancel := context.WithTimeout(m.builder.ctx, time.Duration(m.builder.ttl)*time.Second)
+ util.Go(func(context.Context) {
+ defer cancel()
+ err := backend.Registry().Watch(ctx,
+ registry.WithStrKey(m.builder.key),
+ registry.WithWatchCallback(
+ func(message string, evt *registry.PluginResponse) error {
+ if evt != nil && evt.Action == registry.Delete {
+ // break this for-loop, and try to create the node again.
+ return fmt.Errorf("Lock released")
+ }
+ return nil
+ }))
+ if err != nil {
+ util.Logger().Warnf(nil, "%s, key=%s, id=%s", err.Error(), m.builder.key, m.id)
}
+ })
+ select {
+ case <-ctx.Done():
+ return ctx.Err() // 可以重新尝试获取锁
+ case <-m.builder.ctx.Done():
+ cancel()
+ return m.builder.ctx.Err() // 机制错误,不应该超时的
}
}
func (m *DLock) Unlock() (err error) {
+ defer func() {
+ if !IsDebug {
+ m.builder.mutex.Unlock()
+ }
+ }()
+
opts := []registry.PluginOpOption{
registry.DEL,
registry.WithStrKey(m.builder.key)}
@@ -168,24 +175,15 @@ func (m *DLock) Unlock() (err error) {
for i := 1; i <= DEFAULT_RETRY_TIMES; i++ {
_, err = backend.Registry().Do(m.builder.ctx, opts...)
if err == nil {
- if !IsDebug {
- m.builder.mutex.Unlock()
- }
util.Logger().Infof("Delete lock OK, key=%s, id=%s", m.builder.key, m.id)
return nil
}
- util.Logger().Errorf(err, "Delete lock falied, key=%s, id=%s", m.builder.key, m.id)
+ util.Logger().Errorf(err, "Delete lock failed, key=%s, id=%s", m.builder.key, m.id)
e, ok := err.(client.Error)
if ok && e.Code == client.ErrorCodeKeyNotFound {
- if !IsDebug {
- m.builder.mutex.Unlock()
- }
return nil
}
}
- if !IsDebug {
- m.builder.mutex.Unlock()
- }
return err
}
diff --git a/pkg/etcdsync/mutex_test.go b/pkg/etcdsync/mutex_test.go
index 23a333b..e602388 100644
--- a/pkg/etcdsync/mutex_test.go
+++ b/pkg/etcdsync/mutex_test.go
@@ -14,36 +14,51 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package etcdsync_test
+package etcdsync
import (
- . "github.com/apache/incubator-servicecomb-service-center/pkg/etcdsync"
-
"fmt"
. "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
)
var _ = Describe("Mutex", func() {
Context("normal", func() {
It("TestLockTimeout", func() {
- m1 := NewLockFactory("key1", 10)
- m2 := NewLockFactory("key1", 2)
- m1.NewDLock(true)
+ m1 := NewLockFactory("key1", 5)
+ m2 := NewLockFactory("key1", 1)
+ l1, err := m1.NewDLock(true)
+ Expect(l1).ToNot(BeNil())
+ Expect(err).To(BeNil())
+
fmt.Println("UT===================m1 locked")
ch := make(chan bool)
go func() {
- l, _ := m2.NewDLock(true)
- fmt.Println("UT===================m2 locked")
- l.Unlock()
+ l2, err := m2.NewDLock(false)
+ Expect(l2).To(BeNil())
+ Expect(err).ToNot(BeNil())
+ fmt.Println("UT===================m2 try failed")
+
+ l2, err = m2.NewDLock(true) // 1s * 3
+ Expect(l2).To(BeNil())
+ Expect(err).ToNot(BeNil())
+ fmt.Println("UT===================m2 timed out")
ch <- true
}()
<-ch
- fmt.Println("lock m1 timeout")
+
m3 := NewLockFactory("key1", 2)
- l, _ := m3.NewDLock(true)
+ l3, err := m3.NewDLock(true)
+ Expect(l3).ToNot(BeNil())
+ Expect(err).To(BeNil())
+
fmt.Println("UT===================m3 locked")
- l.Unlock()
+ err = l3.Unlock()
+ Expect(err).To(BeNil())
+ err = l1.Unlock()
+ Expect(err).To(BeNil())
+ fmt.Println("UT===================m1 unlocked")
})
})
})
diff --git a/pkg/rest/client.go b/pkg/rest/client.go
index 6fc15d1..56f7423 100644
--- a/pkg/rest/client.go
+++ b/pkg/rest/client.go
@@ -146,7 +146,9 @@ func (client *HttpClient) httpDo(method string, url string, headers map[string]s
var ok bool = false
bodyBytes, ok = body.([]byte)
if !ok {
- util.Logger().Errorf(nil, "invalid body type '%s'(%s), body must type of byte array if Content-Type specified.", reflect.TypeOf(body), headers[HEADER_CONTENT_TYPE])
+ util.Logger().Errorf(nil,
+ "invalid body type '%s'(%s), body must type of byte array if Content-Type specified.",
+ reflect.TypeOf(body), headers[HEADER_CONTENT_TYPE])
return status, result
}
}
diff --git a/pkg/rest/listener.go b/pkg/rest/listener.go
index 0f119a5..a5f8467 100644
--- a/pkg/rest/listener.go
+++ b/pkg/rest/listener.go
@@ -22,28 +22,27 @@ import (
"syscall"
)
-type restListener struct {
+type TcpListener struct {
net.Listener
stopCh chan error
closed bool
server *Server
}
-func newRestListener(l net.Listener, srv *Server) (el *restListener) {
- el = &restListener{
+func NewTcpListener(l net.Listener, srv *Server) (el *TcpListener) {
+ el = &TcpListener{
Listener: l,
stopCh: make(chan error),
server: srv,
}
go func() {
<-el.stopCh
- el.closed = true
el.stopCh <- el.Listener.Close()
}()
return
}
-func (rl *restListener) Accept() (c net.Conn, err error) {
+func (rl *TcpListener) Accept() (c net.Conn, err error) {
tc, err := rl.Listener.(*net.TCPListener).AcceptTCP()
if err != nil {
return
@@ -63,15 +62,16 @@ func (rl *restListener) Accept() (c net.Conn, err error) {
return
}
-func (rl *restListener) Close() error {
+func (rl *TcpListener) Close() error {
if rl.closed {
return syscall.EINVAL
}
+ rl.closed = true
rl.stopCh <- nil
return <-rl.stopCh
}
-func (rl *restListener) File() *os.File {
+func (rl *TcpListener) File() *os.File {
tl := rl.Listener.(*net.TCPListener)
fl, _ := tl.File()
return fl
diff --git a/pkg/rest/roa.go b/pkg/rest/roa.go
index 63d01c3..f217fad 100644
--- a/pkg/rest/roa.go
+++ b/pkg/rest/roa.go
@@ -40,31 +40,31 @@ func initROAServerHandler() *ROAServerHandler {
}
// servant must be an pointer to service object
-func RegisterServent(servant interface{}) {
+func RegisterServant(servant interface{}) {
val := reflect.ValueOf(servant)
ind := reflect.Indirect(val)
typ := ind.Type()
- name := typ.PkgPath() + "." + typ.Name()
+ name := util.FileLastName(typ.PkgPath() + "." + typ.Name())
if val.Kind() != reflect.Ptr {
- util.Logger().Errorf(nil, "<rest.RegisterServent> cannot use non-ptr servant struct `%s`", name)
+ util.Logger().Errorf(nil, "<rest.RegisterServant> cannot use non-ptr servant struct `%s`", name)
return
}
urlPatternFunc := val.MethodByName("URLPatterns")
if !urlPatternFunc.IsValid() {
- util.Logger().Errorf(nil, "<rest.RegisterServent> no 'URLPatterns' function in servant struct `%s`", name)
+ util.Logger().Errorf(nil, "<rest.RegisterServant> no 'URLPatterns' function in servant struct `%s`", name)
return
}
vals := urlPatternFunc.Call([]reflect.Value{})
if len(vals) <= 0 {
- util.Logger().Errorf(nil, "<rest.RegisterServent> call 'URLPatterns' function failed in servant struct `%s`", name)
+ util.Logger().Errorf(nil, "<rest.RegisterServant> call 'URLPatterns' function failed in servant struct `%s`", name)
return
}
val0 := vals[0]
if !val.CanInterface() {
- util.Logger().Errorf(nil, "<rest.RegisterServent> result of 'URLPatterns' function not interface type in servant struct `%s`", name)
+ util.Logger().Errorf(nil, "<rest.RegisterServant> result of 'URLPatterns' function not interface type in servant struct `%s`", name)
return
}
@@ -77,7 +77,7 @@ func RegisterServent(servant interface{}) {
}
}
} else {
- util.Logger().Errorf(nil, "<rest.RegisterServent> result of 'URLPatterns' function not []*Route type in servant struct `%s`", name)
+ util.Logger().Errorf(nil, "<rest.RegisterServant> result of 'URLPatterns' function not []*Route type in servant struct `%s`", name)
}
}
diff --git a/pkg/rest/server.go b/pkg/rest/server.go
index 4dd7e86..06bbcaa 100644
--- a/pkg/rest/server.go
+++ b/pkg/rest/server.go
@@ -89,9 +89,9 @@ type Server struct {
KeepaliveTimeout time.Duration
GraceTimeout time.Duration
- registerListener net.Listener
- restListener net.Listener
- innerListener *restListener
+ Listener net.Listener
+ netListener net.Listener
+ tcpListener *TcpListener
conns int64
wg sync.WaitGroup
@@ -104,7 +104,7 @@ func (srv *Server) Serve() (err error) {
}()
defer util.RecoverAndReport()
srv.state = serverStateRunning
- err = srv.Server.Serve(srv.restListener)
+ err = srv.Server.Serve(srv.Listener)
util.Logger().Debugf("server serve failed(%s)", err)
srv.wg.Wait()
return
@@ -136,12 +136,12 @@ func (srv *Server) Listen() error {
addr = ":http"
}
- l, err := srv.getListener(addr)
+ l, err := srv.getOrCreateListener(addr)
if err != nil {
return err
}
- srv.restListener = newRestListener(l, srv)
+ srv.Listener = NewTcpListener(l, srv)
grace.RegisterFiles(addr, srv.File())
return nil
}
@@ -152,13 +152,13 @@ func (srv *Server) ListenTLS() error {
addr = ":https"
}
- l, err := srv.getListener(addr)
+ l, err := srv.getOrCreateListener(addr)
if err != nil {
return err
}
- srv.innerListener = newRestListener(l, srv)
- srv.restListener = tls.NewListener(srv.innerListener, srv.TLSConfig)
+ srv.tcpListener = NewTcpListener(l, srv)
+ srv.Listener = tls.NewListener(srv.tcpListener, srv.TLSConfig)
grace.RegisterFiles(addr, srv.File())
return nil
}
@@ -181,7 +181,7 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) (err error) {
}
}
if srv.TLSConfig.NextProtos == nil {
- srv.TLSConfig.NextProtos = []string{"http/1.1"}
+ srv.TLSConfig.NextProtos = []string{"h2", "http/1.1"}
}
err = srv.ListenTLS()
@@ -191,22 +191,19 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) (err error) {
return srv.Serve()
}
+// RegisterListener register the instance created outside by net.Listen() in server
func (srv *Server) RegisterListener(l net.Listener) {
- srv.registerListener = l
+ srv.netListener = l
}
-func (srv *Server) getListener(addr string) (l net.Listener, err error) {
- l = srv.registerListener
- if l != nil {
- return
- }
+func (srv *Server) getOrCreateListener(addr string) (l net.Listener, err error) {
if !grace.IsFork() {
- return net.Listen(srv.Network, addr)
+ return srv.newListener(addr)
}
offset := grace.ExtraFileOrder(addr)
if offset < 0 {
- return net.Listen(srv.Network, addr)
+ return srv.newListener(addr)
}
f := os.NewFile(uintptr(3+offset), "")
@@ -218,13 +215,21 @@ func (srv *Server) getListener(addr string) (l net.Listener, err error) {
return
}
+func (srv *Server) newListener(addr string) (net.Listener, error) {
+ l := srv.netListener
+ if l != nil {
+ return l, nil
+ }
+ return net.Listen(srv.Network, addr)
+}
+
func (srv *Server) Shutdown() {
if srv.state != serverStateRunning {
return
}
srv.state = serverStateTerminating
- err := srv.restListener.Close()
+ err := srv.Listener.Close()
if err != nil {
util.Logger().Errorf(err, "server listener close failed")
}
@@ -264,10 +269,10 @@ func (srv *Server) gracefulStop(d time.Duration) {
}
func (srv *Server) File() *os.File {
- switch srv.restListener.(type) {
- case *restListener:
- return srv.restListener.(*restListener).File()
+ switch srv.Listener.(type) {
+ case *TcpListener:
+ return srv.Listener.(*TcpListener).File()
default:
- return srv.innerListener.File()
+ return srv.tcpListener.File()
}
}
diff --git a/pkg/rpc/grpc.go b/pkg/rpc/grpc.go
index bc47949..eaa9ec7 100644
--- a/pkg/rpc/grpc.go
+++ b/pkg/rpc/grpc.go
@@ -30,7 +30,7 @@ func RegisterService(f RegisterServiceFunc) {
registerFuncs = append(registerFuncs, f)
}
-func RegisterServer(s *grpc.Server) {
+func RegisterGRpcServer(s *grpc.Server) {
for _, f := range registerFuncs {
f(s)
}
diff --git a/pkg/async/executor.go b/pkg/task/executor.go
similarity index 99%
copy from pkg/async/executor.go
copy to pkg/task/executor.go
index d8845e3..6e24285 100644
--- a/pkg/async/executor.go
+++ b/pkg/task/executor.go
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package async
+package task
import (
"errors"
diff --git a/pkg/async/async.go b/pkg/task/service.go
similarity index 93%
rename from pkg/async/async.go
rename to pkg/task/service.go
index 87cc07b..10dad53 100644
--- a/pkg/async/async.go
+++ b/pkg/task/service.go
@@ -14,12 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package async
+package task
import "sync"
var (
- service *TaskService
+ service TaskService
once sync.Once
)
@@ -27,7 +27,7 @@ func init() {
service = NewTaskService()
}
-func Service() *TaskService {
+func Service() TaskService {
once.Do(service.Run)
return service
}
diff --git a/pkg/async/service.go b/pkg/task/service_async.go
similarity index 85%
rename from pkg/async/service.go
rename to pkg/task/service_async.go
index 3551e56..53f8007 100644
--- a/pkg/async/service.go
+++ b/pkg/task/service_async.go
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package async
+package task
import (
"errors"
@@ -35,11 +35,10 @@ const (
type executorWithTTL struct {
*Executor
-
TTL int64
}
-type TaskService struct {
+type AsyncTaskService struct {
executors map[string]*executorWithTTL
goroutine *util.GoRoutine
lock sync.RWMutex
@@ -47,7 +46,7 @@ type TaskService struct {
isClose bool
}
-func (lat *TaskService) getOrNewExecutor(task Task) (s *Executor, isNew bool) {
+func (lat *AsyncTaskService) getOrNewExecutor(task Task) (s *Executor, isNew bool) {
var (
ok bool
key = task.Key()
@@ -73,7 +72,7 @@ func (lat *TaskService) getOrNewExecutor(task Task) (s *Executor, isNew bool) {
return se.Executor, isNew
}
-func (lat *TaskService) Add(ctx context.Context, task Task) error {
+func (lat *AsyncTaskService) Add(ctx context.Context, task Task) error {
if task == nil || ctx == nil {
return errors.New("invalid parameters")
}
@@ -86,14 +85,14 @@ func (lat *TaskService) Add(ctx context.Context, task Task) error {
return s.AddTask(task)
}
-func (lat *TaskService) removeExecutor(key string) {
+func (lat *AsyncTaskService) removeExecutor(key string) {
if s, ok := lat.executors[key]; ok {
s.Close()
delete(lat.executors, key)
}
}
-func (lat *TaskService) LatestHandled(key string) (Task, error) {
+func (lat *AsyncTaskService) LatestHandled(key string) (Task, error) {
lat.lock.RLock()
s, ok := lat.executors[key]
lat.lock.RUnlock()
@@ -103,7 +102,7 @@ func (lat *TaskService) LatestHandled(key string) (Task, error) {
return s.latestTask, nil
}
-func (lat *TaskService) daemon(ctx context.Context) {
+func (lat *AsyncTaskService) daemon(ctx context.Context) {
util.SafeCloseChan(lat.ready)
ticker := time.NewTicker(removeExecutorInterval)
max := 0
@@ -112,7 +111,7 @@ func (lat *TaskService) daemon(ctx context.Context) {
for {
select {
case <-ctx.Done():
- util.Logger().Debugf("daemon thread exited for TaskService is stopped")
+ util.Logger().Debugf("daemon thread exited for AsyncTaskService stopped")
return
case <-timer.C:
lat.lock.RLock()
@@ -166,7 +165,7 @@ func (lat *TaskService) daemon(ctx context.Context) {
}
}
-func (lat *TaskService) Run() {
+func (lat *AsyncTaskService) Run() {
lat.lock.Lock()
if !lat.isClose {
lat.lock.Unlock()
@@ -177,7 +176,7 @@ func (lat *TaskService) Run() {
lat.goroutine.Do(lat.daemon)
}
-func (lat *TaskService) Stop() {
+func (lat *AsyncTaskService) Stop() {
lat.lock.Lock()
if lat.isClose {
lat.lock.Unlock()
@@ -196,11 +195,11 @@ func (lat *TaskService) Stop() {
util.SafeCloseChan(lat.ready)
}
-func (lat *TaskService) Ready() <-chan struct{} {
+func (lat *AsyncTaskService) Ready() <-chan struct{} {
return lat.ready
}
-func (lat *TaskService) renew() {
+func (lat *AsyncTaskService) renew() {
newExecutor := make(map[string]*executorWithTTL)
for k, e := range lat.executors {
newExecutor[k] = e
@@ -208,12 +207,12 @@ func (lat *TaskService) renew() {
lat.executors = newExecutor
}
-func NewTaskService() (lat *TaskService) {
- lat = &TaskService{
+func NewTaskService() TaskService {
+ lat := &AsyncTaskService{
goroutine: util.NewGo(context.Background()),
ready: make(chan struct{}),
isClose: true,
}
lat.renew()
- return
+ return lat
}
diff --git a/pkg/async/async_test.go b/pkg/task/service_test.go
similarity index 99%
rename from pkg/async/async_test.go
rename to pkg/task/service_test.go
index 77593d2..6b4bfe6 100644
--- a/pkg/async/async_test.go
+++ b/pkg/task/service_test.go
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package async
+package task
import (
"testing"
@@ -58,6 +58,7 @@ func (tt *testTask) Do(ctx context.Context) error {
func TestBaseAsyncTasker_AddTask(t *testing.T) {
at := NewTaskService()
at.Run()
+ <-at.Ready()
defer at.Stop()
ctx, cancel := context.WithCancel(context.Background())
diff --git a/pkg/async/task.go b/pkg/task/task.go
similarity index 84%
copy from pkg/async/task.go
copy to pkg/task/task.go
index f4a884f..bff9211 100644
--- a/pkg/async/task.go
+++ b/pkg/task/task.go
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package async
+package task
import "golang.org/x/net/context"
@@ -23,3 +23,12 @@ type Task interface {
Do(ctx context.Context) error
Err() error
}
+
+type TaskService interface {
+ Add(ctx context.Context, task Task) error
+ LatestHandled(key string) (Task, error)
+
+ Run()
+ Stop()
+ Ready() <-chan struct{}
+}
diff --git a/pkg/tlsutil/tlsutil.go b/pkg/tlsutil/tlsutil.go
index 063b30f..b50acd1 100644
--- a/pkg/tlsutil/tlsutil.go
+++ b/pkg/tlsutil/tlsutil.go
@@ -98,8 +98,6 @@ func LoadTLSCertificate(certFile, keyFile, plainPassphase string) (tlsCert []tls
if x509.IsEncryptedPEMBlock(keyBlock) {
plainPassphaseBytes := util.StringToBytesWithNoCopy(plainPassphase)
keyData, err := x509.DecryptPEMBlock(keyBlock, plainPassphaseBytes)
- util.ClearStringMemory(&plainPassphase)
- util.ClearByteMemory(plainPassphaseBytes)
if err != nil {
util.Logger().Errorf(err, "decrypt key file %s failed.", keyFile)
return nil, err
@@ -186,10 +184,12 @@ func GetServerTLSConfig(opts ...SSLConfigOption) (tlsConfig *tls.Config, err err
ClientCAs: pool,
Certificates: certs,
CipherSuites: cfg.CipherSuites,
+ CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256},
PreferServerCipherSuites: true,
ClientAuth: clientAuthMode,
MinVersion: cfg.MinVersion,
MaxVersion: cfg.MaxVersion,
+ NextProtos: []string{"h2", "http/1.1"},
}
return tlsConfig, nil
diff --git a/pkg/tlsutil/tlsutil_test.go b/pkg/tlsutil/tlsutil_test.go
index 4a51f74..fb2dc7d 100644
--- a/pkg/tlsutil/tlsutil_test.go
+++ b/pkg/tlsutil/tlsutil_test.go
@@ -22,6 +22,8 @@ import (
"testing"
)
+const sslRoot = "../../examples/service_center/ssl/"
+
func TestParseDefaultSSLCipherSuites(t *testing.T) {
c := ParseDefaultSSLCipherSuites("")
if c != nil {
@@ -42,7 +44,6 @@ func TestParseDefaultSSLCipherSuites(t *testing.T) {
}
func TestGetServerTLSConfig(t *testing.T) {
- sslRoot := "../../etc/ssl/"
pw, _ := ioutil.ReadFile(sslRoot + "cert_pwd")
opts := append(DefaultServerTLSOptions(),
WithVerifyPeer(true),
@@ -78,7 +79,6 @@ func TestGetServerTLSConfig(t *testing.T) {
}
func TestGetClientTLSConfig(t *testing.T) {
- sslRoot := "../../etc/ssl/"
pw, _ := ioutil.ReadFile(sslRoot + "cert_pwd")
opts := append(DefaultServerTLSOptions(),
WithVerifyPeer(true),
diff --git a/pkg/util/context.go b/pkg/util/context.go
index 565cf69..79fb515 100644
--- a/pkg/util/context.go
+++ b/pkg/util/context.go
@@ -44,7 +44,10 @@ func (c *StringContext) Value(key interface{}) interface{} {
if !ok {
return c.parentCtx.Value(key)
}
- v, _ := c.kv.Get(k)
+ v, ok := c.kv.Get(k)
+ if !ok {
+ return c.parentCtx.Value(key)
+ }
return v
}
@@ -57,7 +60,7 @@ func NewStringContext(ctx context.Context) *StringContext {
if !ok {
strCtx = &StringContext{
parentCtx: ctx,
- kv: NewConcurrentMap(10),
+ kv: NewConcurrentMap(0),
}
}
return strCtx
@@ -74,13 +77,13 @@ func CloneContext(ctx context.Context) context.Context {
if !ok {
return &StringContext{
parentCtx: ctx,
- kv: NewConcurrentMap(10),
+ kv: NewConcurrentMap(0),
}
}
strCtx := &StringContext{
parentCtx: ctx,
- kv: NewConcurrentMap(old.kv.Size()),
+ kv: NewConcurrentMap(0),
}
old.kv.ForEach(func(item MapItem) bool {
diff --git a/pkg/util/context_test.go b/pkg/util/context_test.go
new file mode 100644
index 0000000..4c079b9
--- /dev/null
+++ b/pkg/util/context_test.go
@@ -0,0 +1,77 @@
+/*
+ * 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 util
+
+import (
+ "context"
+ "net/http"
+ "testing"
+)
+
+func TestSetContext(t *testing.T) {
+ ctx := context.WithValue(context.Background(), "z", "z")
+ ctx = context.WithValue(ctx, 1, 1)
+ ctx = SetDomainProject(ctx, "x", "y")
+ if ParseDomainProject(ctx) != "x/y" {
+ t.Fatalf("TestSetContext failed")
+ }
+ if ctx.Value("z") != "z" {
+ t.Fatalf("TestSetContext failed")
+ }
+ if ctx.Value(1) != 1 {
+ t.Fatalf("TestSetContext failed")
+ }
+
+ nctx := CloneContext(ctx)
+ if nctx == ctx {
+ t.Fatalf("TestSetContext failed")
+ }
+ if ParseDomainProject(nctx) != "x/y" {
+ t.Fatalf("TestSetContext failed")
+ }
+ nctx = SetDomainProject(nctx, "x", "x")
+ if ParseDomainProject(ctx) != "x/y" {
+ t.Fatalf("TestSetContext failed")
+ }
+ if ParseDomainProject(nctx) != "x/x" {
+ t.Fatalf("TestSetContext failed")
+ }
+ if nctx.Value("z") != "z" {
+ t.Fatalf("TestSetContext failed")
+ }
+ if nctx.Value(1) != 1 {
+ t.Fatalf("TestSetContext failed")
+ }
+
+ ctx = SetTargetDomainProject(ctx, "x", "x")
+ if ParseTargetDomainProject(ctx) != "x/x" {
+ t.Fatalf("TestSetContext failed")
+ }
+ if ctx.Value("z") != "z" {
+ t.Fatalf("TestSetContext failed")
+ }
+ if ctx.Value(1) != 1 {
+ t.Fatalf("TestSetContext failed")
+ }
+
+ req, _ := http.NewRequest(http.MethodGet, "http://127.0.0.1:30100", nil)
+ ctx = req.Context()
+ SetRequestContext(req, "x", "y")
+ if req.Context() == ctx {
+ t.Fatalf("TestSetContext failed")
+ }
+}
diff --git a/pkg/util/goroutines.go b/pkg/util/goroutines.go
index 74689f3..03d3d43 100644
--- a/pkg/util/goroutines.go
+++ b/pkg/util/goroutines.go
@@ -22,26 +22,50 @@ import (
"time"
)
-var GlobalPoolConfig = &PoolConfig{
- Concurrent: 1000,
- WaitTimeout: time.Second,
- IdleTimeout: 60 * time.Second,
+var GlobalPoolConfig = PoolConfigure()
+
+var defaultGo *GoRoutine
+
+func init() {
+ defaultGo = NewGo(context.Background())
}
type PoolConfig struct {
Concurrent int
- WaitTimeout time.Duration
IdleTimeout time.Duration
}
+func (c *PoolConfig) Workers(max int) *PoolConfig {
+ c.Concurrent = max
+ return c
+}
+
+func (c *PoolConfig) Idle(time time.Duration) *PoolConfig {
+ c.IdleTimeout = time
+ return c
+}
+
+func PoolConfigure() *PoolConfig {
+ return &PoolConfig{
+ Concurrent: 1000,
+ IdleTimeout: 60 * time.Second,
+ }
+}
+
type GoRoutine struct {
- ctx context.Context
- cancel context.CancelFunc
- wg sync.WaitGroup
- mux sync.RWMutex
- closed bool
- task chan func(ctx context.Context)
- concurrent chan struct{}
+ Cfg *PoolConfig
+
+ // job context
+ ctx context.Context
+ cancel context.CancelFunc
+ // pending is the chan to block GoRoutine.Do() when go pool is full
+ pending chan func(ctx context.Context)
+ // workers is the counter of the worker
+ workers chan struct{}
+
+ mux sync.RWMutex
+ wg sync.WaitGroup
+ closed bool
}
func (g *GoRoutine) execute(f func(ctx context.Context)) {
@@ -49,22 +73,22 @@ func (g *GoRoutine) execute(f func(ctx context.Context)) {
f(g.ctx)
}
-func (g *GoRoutine) Do(f func(context.Context)) {
+func (g *GoRoutine) Do(f func(context.Context)) *GoRoutine {
defer RecoverAndReport()
select {
- case g.task <- f:
- return
- case g.concurrent <- struct{}{}:
+ case g.pending <- f:
+ case g.workers <- struct{}{}:
+ g.wg.Add(1)
go g.loop(f)
}
+ return g
}
func (g *GoRoutine) loop(f func(context.Context)) {
- g.wg.Add(1)
defer g.wg.Done()
- defer func() { <-g.concurrent }()
+ defer func() { <-g.workers }()
- timer := time.NewTimer(GlobalPoolConfig.IdleTimeout)
+ timer := time.NewTimer(g.Cfg.IdleTimeout)
defer timer.Stop()
for {
g.execute(f)
@@ -72,16 +96,17 @@ func (g *GoRoutine) loop(f func(context.Context)) {
select {
case <-timer.C:
return
- case f = <-g.task:
+ case f = <-g.pending:
if f == nil {
return
}
- ResetTimer(timer, GlobalPoolConfig.IdleTimeout)
+ ResetTimer(timer, g.Cfg.IdleTimeout)
}
}
}
-func (g *GoRoutine) Close(wait bool) {
+// Close will call context.Cancel(), so all goroutines maybe exit when job does not complete
+func (g *GoRoutine) Close(grace bool) {
g.mux.Lock()
if g.closed {
g.mux.Unlock()
@@ -90,22 +115,43 @@ func (g *GoRoutine) Close(wait bool) {
g.closed = true
g.mux.Unlock()
- close(g.task)
- close(g.concurrent)
+ close(g.pending)
+ close(g.workers)
g.cancel()
- if wait {
- g.Wait()
+ if grace {
+ g.wg.Wait()
}
}
-func (g *GoRoutine) Wait() {
+// Done will wait for all goroutines complete the jobs and then close the pool
+func (g *GoRoutine) Done() {
+ g.mux.Lock()
+ if g.closed {
+ g.mux.Unlock()
+ return
+ }
+ g.closed = true
+ g.mux.Unlock()
+
+ close(g.pending)
+ close(g.workers)
g.wg.Wait()
}
-var defaultGo *GoRoutine
-
-func init() {
- defaultGo = NewGo(context.Background())
+func NewGo(ctx context.Context, cfgs ...*PoolConfig) *GoRoutine {
+ ctx, cancel := context.WithCancel(ctx)
+ if len(cfgs) == 0 {
+ cfgs = append(cfgs, GlobalPoolConfig)
+ }
+ cfg := cfgs[0]
+ gr := &GoRoutine{
+ Cfg: cfg,
+ ctx: ctx,
+ cancel: cancel,
+ pending: make(chan func(context.Context)),
+ workers: make(chan struct{}, cfg.Concurrent),
+ }
+ return gr
}
func Go(f func(context.Context)) {
@@ -116,14 +162,3 @@ func GoCloseAndWait() {
defaultGo.Close(true)
Logger().Debugf("all goroutines exited")
}
-
-func NewGo(ctx context.Context) *GoRoutine {
- ctx, cancel := context.WithCancel(ctx)
- gr := &GoRoutine{
- ctx: ctx,
- cancel: cancel,
- task: make(chan func(context.Context)),
- concurrent: make(chan struct{}, GlobalPoolConfig.Concurrent),
- }
- return gr
-}
diff --git a/pkg/util/goroutines_test.go b/pkg/util/goroutines_test.go
index fe14e19..997ca95 100644
--- a/pkg/util/goroutines_test.go
+++ b/pkg/util/goroutines_test.go
@@ -55,12 +55,10 @@ func TestGoRoutine_Do(t *testing.T) {
}
func TestGoRoutine_Wait(t *testing.T) {
- GlobalPoolConfig.IdleTimeout = time.Second
-
var mux sync.Mutex
MAX := 10
resultArr := make([]int, 0, MAX)
- test := NewGo(context.Background())
+ test := NewGo(context.Background(), PoolConfigure().Idle(time.Second).Workers(5))
for i := 0; i < MAX; i++ {
test.Do(func(ctx context.Context) {
select {
@@ -75,14 +73,14 @@ func TestGoRoutine_Wait(t *testing.T) {
}
<-time.After(time.Second)
fmt.Println("waiting for all goroutines finish.")
- test.Wait()
+ test.Done()
fmt.Println(resultArr)
if len(resultArr) != MAX {
t.Fatalf("fail to wait all goroutines finish. expected %d to %d", len(resultArr), MAX)
}
}
-func TestGoRoutine_Close(t *testing.T) {
+func TestGoRoutine_Exception1(t *testing.T) {
test := NewGo(context.Background())
test.Do(func(ctx context.Context) {
select {
@@ -98,11 +96,11 @@ func TestGoRoutine_Close(t *testing.T) {
t.Fatalf("can not execute f after closed.")
}
})
- test.Wait()
+ test.Done()
test.Close(true)
}
-func TestGo(t *testing.T) {
+func TestGoRoutine_Exception2(t *testing.T) {
Go(func(ctx context.Context) {
for {
select {
diff --git a/pkg/util/log.go b/pkg/util/log.go
index bc82a89..38d8051 100644
--- a/pkg/util/log.go
+++ b/pkg/util/log.go
@@ -31,10 +31,10 @@ import (
//log var
var (
- LOGGER lager.Logger
- defaultLagerConfig = stlager.DefaultConfig()
- loggerConfig LoggerConfig
- logLevel lager.LogLevel
+ globalLogger lager.Logger
+ globalConfig LoggerConfig
+ innerLagerConfig = stlager.DefaultConfig()
+ logLevel lager.LogLevel
loggers map[string]lager.Logger
loggerNames map[string]string
@@ -57,8 +57,8 @@ type LoggerConfig struct {
func init() {
loggers = make(map[string]lager.Logger, 10)
loggerNames = make(map[string]string, 10)
- // make LOGGER do not be nil, new a stdout logger
- LOGGER = NewLogger(fromLagerConfig(defaultLagerConfig))
+ // make globalLogger do not be nil, new a stdout for it
+ globalLogger = NewLogger(fromLagerConfig(innerLagerConfig))
}
func fromLagerConfig(c *stlager.Config) LoggerConfig {
@@ -89,14 +89,12 @@ func NewLogger(cfg LoggerConfig) lager.Logger {
}
func InitGlobalLogger(cfg LoggerConfig) {
- // renew the global logger
+ // renew the global globalLogger
if len(cfg.LoggerLevel) == 0 {
- cfg.LoggerLevel = defaultLagerConfig.LoggerLevel
+ cfg.LoggerLevel = innerLagerConfig.LoggerLevel
}
- loggerConfig = cfg
- LOGGER = NewLogger(cfg)
- // log rotate
- RunLogDirRotate(cfg)
+ globalConfig = cfg
+ globalLogger = NewLogger(cfg)
// recreate the deleted log file
switch strings.ToUpper(cfg.LoggerLevel) {
case "INFO":
@@ -110,12 +108,15 @@ func InitGlobalLogger(cfg LoggerConfig) {
default:
logLevel = lager.DEBUG
}
+
+ RunLogDirRotate(cfg)
+
monitorLogFile()
}
func Logger() lager.Logger {
if len(loggerNames) == 0 {
- return LOGGER
+ return globalLogger
}
funcFullName := getCalleeFuncName()
@@ -141,19 +142,19 @@ func Logger() lager.Logger {
loggersMux.Lock()
logger, ok = loggers[logFile]
if !ok {
- cfg := loggerConfig
+ cfg := globalConfig
if len(cfg.LoggerFile) != 0 {
cfg.LoggerFile = filepath.Join(filepath.Dir(cfg.LoggerFile), logFile+".log")
}
logger = NewLogger(cfg)
loggers[logFile] = logger
- LOGGER.Warnf(nil, "match %s, new logger %s for %s", prefix, logFile, funcFullName)
+ logger.Warnf(nil, "match %s, new globalLogger %s for %s", prefix, logFile, funcFullName)
}
loggersMux.Unlock()
return logger
}
- return LOGGER
+ return globalLogger
}
func getCalleeFuncName() string {
@@ -188,7 +189,7 @@ func CustomLogger(pkgOrFunc, fileName string) {
}
func monitorLogFile() {
- if len(loggerConfig.LoggerFile) == 0 {
+ if len(globalConfig.LoggerFile) == 0 {
return
}
Go(func(ctx context.Context) {
@@ -198,18 +199,20 @@ func monitorLogFile() {
return
case <-time.After(time.Minute):
Logger().Debug(fmt.Sprintf("Check log file at %s", time.Now()))
+ if PathExist(globalConfig.LoggerFile) {
+ continue
+ }
- if !PathExist(loggerConfig.LoggerFile) {
- file, err := os.OpenFile(loggerConfig.LoggerFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
- if err != nil {
- Logger().Errorf(err, "Create log file failed.")
- return
- }
- // TODO Here will lead to file handle leak
- sink := lager.NewReconfigurableSink(lager.NewWriterSink("file", file, lager.DEBUG), logLevel)
- Logger().RegisterSink(sink)
- Logger().Errorf(nil, "log file is removed, create again.")
+ file, err := os.OpenFile(globalConfig.LoggerFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
+ if err != nil {
+ Logger().Errorf(err, "Create log file failed.")
+ continue
}
+
+ // TODO Here will lead to file handle leak
+ sink := lager.NewReconfigurableSink(lager.NewWriterSink("file", file, lager.DEBUG), logLevel)
+ Logger().RegisterSink(sink)
+ Logger().Errorf(nil, "log file is removed, create again.")
}
}
})
diff --git a/pkg/util/log_test.go b/pkg/util/log_test.go
index d513e22..9d0bdbf 100644
--- a/pkg/util/log_test.go
+++ b/pkg/util/log_test.go
@@ -18,29 +18,42 @@ package util
import (
"testing"
+ "time"
)
func TestLogger(t *testing.T) {
+ InitGlobalLogger(LoggerConfig{
+ LoggerLevel: "DEBUG",
+ })
+
CustomLogger("Not Exist", "testDefaultLOGGER")
l := Logger()
- if l != LOGGER {
- t.Fatalf("should equal to LOGGER")
+ if l != globalLogger {
+ t.Fatalf("should equal to globalLogger")
}
CustomLogger("TestLogger", "testFuncName")
l = Logger()
- if l == LOGGER || l == nil {
+ if l == globalLogger || l == nil {
t.Fatalf("should create a new instance for 'TestLogger'")
}
s := Logger()
if l != s {
- t.Fatalf("should be the same logger")
+ t.Fatalf("should be the same globalLogger")
}
CustomLogger("github.com/apache/incubator-servicecomb-service-center/pkg/util", "testPkgPath")
l = Logger()
- if l == LOGGER || l == nil {
+ if l == globalLogger || l == nil {
t.Fatalf("should create a new instance for 'util'")
}
// l.Infof("OK")
+
+ LogDebugOrWarnf(time.Now().Add(-time.Second), "x")
+ LogNilOrWarnf(time.Now().Add(-time.Second), "x")
+ LogInfoOrWarnf(time.Now().Add(-time.Second), "x")
+
+ LogDebugOrWarnf(time.Now(), "x")
+ LogNilOrWarnf(time.Now(), "x")
+ LogInfoOrWarnf(time.Now(), "x")
}
func BenchmarkLogger(b *testing.B) {
diff --git a/pkg/util/logrotate.go b/pkg/util/logrotate.go
index 919ee72..138677d 100644
--- a/pkg/util/logrotate.go
+++ b/pkg/util/logrotate.go
@@ -295,6 +295,9 @@ func CopyFile(srcFile, destFile string) error {
}
func RunLogDirRotate(cfg LoggerConfig) {
+ if len(cfg.LoggerFile) == 0 {
+ return
+ }
Go(func(ctx context.Context) {
for {
select {
diff --git a/pkg/util/logrotate_test.go b/pkg/util/logrotate_test.go
index 407baa5..4ffad2f 100644
--- a/pkg/util/logrotate_test.go
+++ b/pkg/util/logrotate_test.go
@@ -17,6 +17,7 @@
package util
import (
+ "os"
"testing"
)
@@ -25,4 +26,20 @@ func TestLogRotate(t *testing.T) {
if s != "./sc.log" {
t.Fatal("pathReplacer failed", s)
}
+
+ LogRotate("../../etc", 1, 1)
+
+ LogRotateFile("../../etc/conf/app.conf", 1, 1)
+
+ if err := compressFile(
+ "../../etc/conf/app.conf",
+ "app",
+ false); err != nil {
+ t.Fatal("TestLogRotate failed", err)
+ }
+
+ os.Chmod("../../etc/conf/app.conf.zip", 0640)
+ if err := removeFile("../../etc/conf/app.conf.zip"); err != nil {
+ t.Fatal("TestLogRotate failed", err)
+ }
}
diff --git a/pkg/util/net.go b/pkg/util/net.go
index 6082506..c304933 100644
--- a/pkg/util/net.go
+++ b/pkg/util/net.go
@@ -38,18 +38,6 @@ func GetIPFromContext(ctx context.Context) string {
return v
}
-func UrlEncode(keys map[string]string) string {
- l := len(keys)
- if l == 0 {
- return ""
- }
- arr := make([]string, 0, l)
- for k, v := range keys {
- arr = append(arr, url.QueryEscape(k)+"="+url.QueryEscape(v))
- }
- return StringJoin(arr, "&")
-}
-
func ParseEndpoint(ep string) (string, error) {
u, err := url.Parse(ep)
if err != nil {
@@ -79,11 +67,7 @@ func GetRealIP(r *http.Request) string {
return ip
}
}
- addrs := strings.Split(r.RemoteAddr, ":")
- if len(addrs) > 0 {
- return addrs[0]
- }
- return ""
+ return strings.Split(r.RemoteAddr, ":")[0]
}
func InetNtoIP(ipnr uint32) net.IP {
diff --git a/pkg/util/net_test.go b/pkg/util/net_test.go
index 0116f3d..a5dbfdf 100644
--- a/pkg/util/net_test.go
+++ b/pkg/util/net_test.go
@@ -16,7 +16,10 @@
*/
package util
-import "testing"
+import (
+ "net/http"
+ "testing"
+)
const (
ip1 = "127.0.0.1" // 2130706433
@@ -94,3 +97,45 @@ func TestParseEndpoint(t *testing.T) {
t.Fatalf("ParseEndpoint(\"rest://[fe80::f816:3eff:fe17:c38b%%25eht0]:30100/?a=b\") failed, err = %s, ep = %s", err, ep)
}
}
+
+func TestParseRequestURL(t *testing.T) {
+ req, _ := http.NewRequest(http.MethodGet, "https://127.0.0.1:30100/x/?a=b&c=d#e", nil)
+ url := ParseRequestURL(req)
+ if url != "https://127.0.0.1:30100/x/?a=b&c=d#e" {
+ t.Fatalf("TestParseRequestURL failed")
+ }
+ req.URL.Scheme = ""
+ req.Host = "127.0.0.1:30100"
+ req.RequestURI = "/x/?a=b&c=d#e"
+ url = ParseRequestURL(req)
+ if url != "http://127.0.0.1:30100/x/?a=b&c=d#e" {
+ t.Fatalf("TestParseRequestURL failed")
+ }
+}
+
+func TestGetRealIP(t *testing.T) {
+ req, _ := http.NewRequest(http.MethodGet, "https://127.0.0.1:30100/x/?a=b&c=d#e", nil)
+ req.RemoteAddr = "127.0.0.1:30100"
+ ip := GetRealIP(req)
+ if ip != "127.0.0.1" {
+ t.Fatalf("TestGetRealIP failed")
+ }
+
+ req.Header.Set("X-Real-Ip", "255.255.255.255")
+ ip = GetRealIP(req)
+ if ip != "127.0.0.1" {
+ t.Fatalf("TestGetRealIP failed")
+ }
+
+ req.Header.Set("X-Real-Ip", "4.4.4.4")
+ ip = GetRealIP(req)
+ if ip != "4.4.4.4" {
+ t.Fatalf("TestGetRealIP failed")
+ }
+
+ req.Header.Set("X-Forwarded-For", "1.1.1.1, 2.2.2.2, 3.3.3.3")
+ ip = GetRealIP(req)
+ if ip != "1.1.1.1" {
+ t.Fatalf("TestGetRealIP failed")
+ }
+}
diff --git a/pkg/util/reflect.go b/pkg/util/reflect.go
index 695a7b9..73a5466 100644
--- a/pkg/util/reflect.go
+++ b/pkg/util/reflect.go
@@ -18,6 +18,8 @@ package util
import (
"reflect"
+ "runtime"
+ "strings"
"sync"
"unsafe"
)
@@ -26,25 +28,34 @@ var (
reflector *Reflector
sliceTypeSize = uint64(reflect.TypeOf(reflect.SliceHeader{}).Size())
stringTypeSize = uint64(reflect.TypeOf(reflect.StringHeader{}).Size())
+ unknown = new(reflectObject)
)
func init() {
reflector = &Reflector{
- types: make(map[*uintptr]reflectObject, 100),
+ types: make(map[*uintptr]*reflectObject),
}
}
type reflectObject struct {
- Type reflect.Type
+ // full name
+ FullName string
+ Type reflect.Type
+ // if type is not struct, Fields is nil
Fields []reflect.StructField
}
+// Name returns a short name of the object type
+func (o *reflectObject) Name() string {
+ return FileLastName(o.FullName)
+}
+
type Reflector struct {
- types map[*uintptr]reflectObject
+ types map[*uintptr]*reflectObject
mux sync.RWMutex
}
-func (r *Reflector) Load(obj interface{}) reflectObject {
+func (r *Reflector) Load(obj interface{}) *reflectObject {
r.mux.RLock()
itab := *(**uintptr)(unsafe.Pointer(&obj))
t, ok := r.types[itab]
@@ -60,38 +71,48 @@ func (r *Reflector) Load(obj interface{}) reflectObject {
return t
}
+ t = new(reflectObject)
v := reflect.ValueOf(obj)
if !v.IsValid() {
r.mux.Unlock()
- return reflectObject{}
+ return unknown
}
switch v.Kind() {
case reflect.Ptr:
- if v.IsNil() {
- r.mux.Unlock()
- return reflectObject{}
- }
fallthrough
case reflect.Interface:
r.mux.Unlock()
- return r.Load(v.Elem().Interface())
- default:
- t = reflectObject{
- Type: reflect.TypeOf(obj),
+ if v.IsNil() {
+ return unknown
}
- }
-
- if v.Kind() != reflect.Struct {
- r.mux.Unlock()
- return t
- }
+ e := v.Elem()
+ if e.CanInterface() {
+ return r.Load(e.Interface())
+ }
+ return unknown
+ default:
+ t.Type = reflect.TypeOf(obj)
- fl := t.Type.NumField()
- if fl > 0 {
- t.Fields = make([]reflect.StructField, fl)
- for i := 0; i < fl; i++ {
- f := t.Type.Field(i)
- t.Fields[i] = f
+ switch v.Kind() {
+ case reflect.Func:
+ r.mux.Unlock()
+ f := runtime.FuncForPC(v.Pointer())
+ if f == nil {
+ return unknown
+ }
+ t.FullName = f.Name()
+ return t
+ case reflect.Struct:
+ if fl := t.Type.NumField(); fl > 0 {
+ t.Fields = make([]reflect.StructField, fl)
+ for i := 0; i < fl; i++ {
+ f := t.Type.Field(i)
+ t.Fields[i] = f
+ }
+ }
+ fallthrough
+ default:
+ t.FullName = t.Type.PkgPath() + "." + t.Type.Name()
}
}
r.types[itab] = t
@@ -99,7 +120,7 @@ func (r *Reflector) Load(obj interface{}) reflectObject {
return t
}
-func ReflectObject(obj interface{}) (s reflectObject) {
+func Reflect(obj interface{}) *reflectObject {
return reflector.Load(obj)
}
@@ -181,3 +202,18 @@ func isValueType(kind reflect.Kind) bool {
return false
}
}
+
+func FormatFuncName(f string) string {
+ i := strings.LastIndex(f, "/")
+ j := strings.Index(f[i+1:], ".")
+ if j < 1 {
+ return "???"
+ }
+ _, fun := f[:i+j+1], f[i+j+2:]
+ i = strings.LastIndex(fun, ".")
+ return fun[i+1:]
+}
+
+func FuncName(f interface{}) string {
+ return Reflect(f).Name()
+}
diff --git a/pkg/util/reflect_test.go b/pkg/util/reflect_test.go
index f5a4c51..d6706ca 100644
--- a/pkg/util/reflect_test.go
+++ b/pkg/util/reflect_test.go
@@ -18,7 +18,6 @@ package util
import (
"fmt"
- "reflect"
"testing"
)
@@ -34,47 +33,69 @@ type testField struct {
func TestLoadStruct(t *testing.T) {
obj1 := testStru{}
- v := ReflectObject(obj1)
+ v := Reflect(obj1)
if v.Type.String() != "util.testStru" {
t.Fatalf("TestLoadStruct failed, %s != 'testStru'", v.Type.String())
}
if len(v.Fields) != 4 {
t.Fatalf("TestLoadStruct failed, wrong count of fields")
}
+ if v.Name() != "pkg/util.testStru" || v.FullName != "github.com/apache/incubator-servicecomb-service-center/pkg/util.testStru" {
+ t.Fatalf("TestLoadStruct failed")
+ }
for _, f := range v.Fields {
fmt.Println(f.Name, f.Type.String())
}
obj2 := testStru{}
- v = ReflectObject(obj2)
- v = ReflectObject(&obj2)
- v = ReflectObject(nil)
+ v1 := Reflect(obj2)
+ if v1.FullName != v.FullName {
+ t.Fatalf("TestLoadStruct failed")
+ }
+ v2 := Reflect(&obj2)
+ if v2.FullName != v.FullName {
+ t.Fatalf("TestLoadStruct failed")
+ }
+ v = Reflect(nil)
+ if v.FullName != "" {
+ t.Fatalf("TestLoadStruct failed")
+ }
+
+ if FuncName(TestLoadStruct) != "pkg/util.TestLoadStruct" {
+ t.Fatalf("TestLoadStruct failed")
+ }
+ f := TestLoadStruct
+ if FormatFuncName(FuncName(f)) != "TestLoadStruct" {
+ t.Fatalf("TestLoadStruct failed")
+ }
+}
+
+func TestSizeof(t *testing.T) {
+ s := &S{}
+ if Sizeof(s) != 8+152 {
+ t.Fatalf("TestSizeof failed")
+ }
}
func BenchmarkLoadStruct(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
- ReflectObject(testStru{})
+ Reflect(testStru{})
}
})
b.ReportAllocs()
// 20000000 86.9 ns/op 32 B/op 1 allocs/op
}
-var (
- sliceSize = uint64(reflect.TypeOf(reflect.SliceHeader{}).Size())
- stringSize = uint64(reflect.TypeOf(reflect.StringHeader{}).Size())
-)
-
type S struct {
- a int
- s string
- p *S
- m map[int32]uint32
- u []uint64
- ua [8]uint64
- ch chan int
- i interface{}
+ a int // 8
+ s string // 16
+ p *S // 8
+ m map[int32]uint32 // 8
+ u []uint64 // 24
+ ua [8]uint64 // 64
+ ch chan int // 8
+ i interface{} // 16
}
func BenchmarkSizeof(b *testing.B) {
diff --git a/pkg/util/util.go b/pkg/util/util.go
index 5c3b3f0..d1dfd0c 100644
--- a/pkg/util/util.go
+++ b/pkg/util/util.go
@@ -17,11 +17,8 @@
package util
import (
- "bytes"
- "encoding/gob"
"fmt"
"os"
- "reflect"
"runtime"
"runtime/debug"
"strings"
@@ -29,45 +26,11 @@ import (
"unsafe"
)
-func MinInt(x, y int) int {
- if x <= y {
- return x
- } else {
- return y
- }
-}
-
-func ClearStringMemory(src *string) {
- p := (*struct {
- ptr uintptr
- len int
- })(unsafe.Pointer(src))
-
- l := MinInt(p.len, 32)
- ptr := p.ptr
- for idx := 0; idx < l; idx = idx + 1 {
- b := (*byte)(unsafe.Pointer(ptr))
- *b = 0
- ptr += 1
- }
-}
-
-func ClearByteMemory(src []byte) {
- l := MinInt(len(src), 32)
- for idx := 0; idx < l; idx = idx + 1 {
- src[idx] = 0
+func SafeCloseChan(c chan struct{}) {
+ if c == nil {
+ return
}
-}
-func DeepCopy(dst, src interface{}) error {
- var buf bytes.Buffer
- if err := gob.NewEncoder(&buf).Encode(src); err != nil {
- return err
- }
- return gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(dst)
-}
-
-func SafeCloseChan(c chan struct{}) {
select {
case _, ok := <-c:
if ok {
@@ -133,6 +96,12 @@ func RecoverAndReport() (r interface{}) {
return
}
+func GetCaller(skip int) (string, string, int, bool) {
+ pc, file, line, ok := runtime.Caller(skip + 1)
+ method := FormatFuncName(runtime.FuncForPC(pc).Name())
+ return file, method, line, ok
+}
+
// this function can only be called in recover().
func LogPanic(args ...interface{}) {
for i := 2; i < 10; i++ {
@@ -153,21 +122,6 @@ func LogPanic(args ...interface{}) {
fmt.Fprintln(os.Stderr, BytesToStringWithNoCopy(debug.Stack()))
}
-func FileLastName(file string) string {
- if sp1 := strings.LastIndex(file, "/"); sp1 >= 0 {
- if sp2 := strings.LastIndex(file[:sp1], "/"); sp2 >= 0 {
- file = file[sp2+1:]
- }
- }
- return file
-}
-
-func GetCaller(skip int) (string, string, int, bool) {
- pc, file, line, ok := runtime.Caller(skip + 1)
- method := FormatFuncName(runtime.FuncForPC(pc).Name())
- return file, method, line, ok
-}
-
func Int16ToInt64(bs []int16) (in int64) {
l := len(bs)
if l > 4 || l == 0 {
@@ -188,19 +142,13 @@ func Int16ToInt64(bs []int16) (in int64) {
return
}
-func FormatFuncName(f string) string {
- i := strings.LastIndex(f, "/")
- j := strings.Index(f[i+1:], ".")
- if j < 1 {
- return "???"
+func FileLastName(file string) string {
+ if sp1 := strings.LastIndex(file, "/"); sp1 >= 0 {
+ if sp2 := strings.LastIndex(file[:sp1], "/"); sp2 >= 0 {
+ file = file[sp2+1:]
+ }
}
- _, fun := f[:i+j+1], f[i+j+2:]
- i = strings.LastIndex(fun, ".")
- return fun[i+1:]
-}
-
-func FuncName(f interface{}) string {
- return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
+ return file
}
func SliceHave(arr []string, str string) bool {
diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go
index c50ae81..852851f 100644
--- a/pkg/util/util_test.go
+++ b/pkg/util/util_test.go
@@ -80,3 +80,45 @@ func TestResetTimer(t *testing.T) {
ResetTimer(timer, time.Second)
<-timer.C
}
+
+func TestStringJoin(t *testing.T) {
+ if StringJoin([]string{"a", "b", "c"}, ",") != "a,b,c" {
+ t.Fatalf("TestStringJoin failed")
+ }
+ if StringJoin([]string{"a"}, ",") != "a" {
+ t.Fatalf("TestStringJoin failed")
+ }
+ if StringJoin([]string{"a", "b", "c"}, "") != "abc" {
+ t.Fatalf("TestStringJoin failed")
+ }
+ if StringJoin([]string{}, ",") != "" {
+ t.Fatalf("TestStringJoin failed")
+ }
+ if StringJoin(nil, ",") != "" {
+ t.Fatalf("TestStringJoin failed")
+ }
+}
+
+func TestStringToBytesWithNoCopy(t *testing.T) {
+ b := StringToBytesWithNoCopy("ab")
+ if b[0] != 'a' || b[1] != 'b' {
+ t.Fatalf("TestStringToBytesWithNoCopy failed")
+ }
+}
+
+func TestSafeCloseChan(t *testing.T) {
+ var ch chan struct{}
+ SafeCloseChan(ch)
+ ch = make(chan struct{})
+ SafeCloseChan(ch)
+ SafeCloseChan(ch)
+}
+
+func TestSystemPackage(t *testing.T) {
+ if HostName() == "" {
+ t.Fatalf("TestSystemPackage failed")
+ }
+ if !PathExist("../../etc/conf/app.conf") {
+ t.Fatalf("TestSystemPackage failed")
+ }
+}
diff --git a/pkg/util/logrotate_test.go b/pkg/util/uuid_test.go
similarity index 83%
copy from pkg/util/logrotate_test.go
copy to pkg/util/uuid_test.go
index 407baa5..392db1c 100644
--- a/pkg/util/logrotate_test.go
+++ b/pkg/util/uuid_test.go
@@ -17,12 +17,13 @@
package util
import (
+ "strings"
"testing"
)
-func TestLogRotate(t *testing.T) {
- s := pathReplacer.Replace("./sc.log")
- if s != "./sc.log" {
- t.Fatal("pathReplacer failed", s)
+func TestGenerateUuid(t *testing.T) {
+ uuid := GenerateUuid()
+ if len(uuid) == 0 || strings.Contains(uuid, "-") {
+ t.Fatalf("TestGenerateUuid failed")
}
}
diff --git a/pkg/validate/url.go b/pkg/validate/url.go
index f41eaa4..824d0a4 100644
--- a/pkg/validate/url.go
+++ b/pkg/validate/url.go
@@ -17,53 +17,24 @@
package validate
import (
- "net/url"
- "regexp"
"strings"
)
-const (
- PATTERN_URI string = `#%`
- PATTERN_URL = "^(https|http):\\/\\/((?:(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d)))\\.){3}(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d)))):([0-9]+)$"
- PATTERN_HOSTNAME string = `^(([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4])))(:(\d{1,5}))$`
-)
-
-var (
- rxURI = regexp.MustCompile(PATTERN_URI)
- rxURL = regexp.MustCompile(PATTERN_URL)
- rxHostName = regexp.MustCompile(PATTERN_HOSTNAME)
-)
-
-// IsURL check if the string is an URL.
-func IsURL(str string) bool {
- if str == "" || len(str) >= 2083 || len(str) <= 3 || strings.HasPrefix(str, ".") {
- return false
- }
- u, err := url.Parse(str)
- if err != nil {
- return false
- }
- if strings.HasPrefix(u.Host, ".") {
- return false
- }
- if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) {
- return false
- }
- return rxHostName.MatchString(str)
-
-}
-
+// IsRequestURI check if the string is an URL.
func IsRequestURI(uri string) bool {
- if uri == "" || len(uri) >= 2048 || strings.HasPrefix(uri, ".") {
+ if uri == "" || len(uri) >= 2048 {
return false
}
- if strings.HasSuffix(uri, ";") || strings.HasSuffix(uri, "&") || strings.HasSuffix(uri, "?") || strings.HasSuffix(uri, "+") || strings.HasSuffix(uri, "@") || strings.Contains(uri, "//") {
+ if strings.HasSuffix(uri, ";") ||
+ strings.HasSuffix(uri, "&") ||
+ strings.HasSuffix(uri, "?") ||
+ strings.HasSuffix(uri, "+") ||
+ strings.HasSuffix(uri, "@") ||
+ //
+ strings.HasPrefix(uri, ".") ||
+ //
+ strings.Contains(uri, "//") {
return false
}
- return !rxURI.MatchString(uri)
-}
-
-//format : https://10.21.119.167:30100 or http://10.21.119.167:30100
-func URLChecker(url string) bool {
- return rxURL.MatchString(url)
+ return true
}
diff --git a/pkg/validate/validator.go b/pkg/validate/validator.go
index d7f5c70..7a68301 100644
--- a/pkg/validate/validator.go
+++ b/pkg/validate/validator.go
@@ -105,7 +105,7 @@ func (v *Validator) Validate(s interface{}) error {
return fmt.Errorf("not support validate type '%s'", k)
}
- st := util.ReflectObject(s)
+ st := util.Reflect(s)
for i, l := 0, sv.NumField(); i < l; i++ {
field := sv.Field(i)
fieldName := st.Fields[i].Name
diff --git a/scripts/prepare_env_ut.sh b/scripts/prepare_env_ut.sh
index a92980f..2868ee1 100755
--- a/scripts/prepare_env_ut.sh
+++ b/scripts/prepare_env_ut.sh
@@ -14,6 +14,5 @@
# 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.
-cp -r etc/conf server/interceptor/ratelimiter/
-cp -r etc/conf server/service/
+cp -r etc/conf server/plugin/infra/tls/buildin
echo "mode: atomic" > coverage.txt
diff --git a/scripts/ut_test_in_docker.sh b/scripts/ut_test_in_docker.sh
index fed3fbe..944e163 100755
--- a/scripts/ut_test_in_docker.sh
+++ b/scripts/ut_test_in_docker.sh
@@ -37,9 +37,14 @@ echo "${green}Preparing the env for UT....${reset}"
./scripts/prepare_env_ut.sh
echo "${green}Running UT for Service-Center server"
-bash -x ./scripts/ut.sh server/service
-
-if [ $? == 0 ]; then
+bash -x ./scripts/ut.sh pkg
+ret=$?
+if [ ${ret} == 0 ]; then
+ bash -x ./scripts/ut.sh server
+ ret=$?
+fi
+
+if [ ${ret} == 0 ]; then
echo "${green}All the unit test passed..${reset}"
echo "${green}Coverage is created in the file ./coverage.txt${reset}"
else
diff --git a/server/broker/broker.go b/server/admin/admin.go
similarity index 93%
copy from server/broker/broker.go
copy to server/admin/admin.go
index fc807be..4a7da27 100644
--- a/server/broker/broker.go
+++ b/server/admin/admin.go
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package broker
+package admin
import (
roa "github.com/apache/incubator-servicecomb-service-center/pkg/rest"
@@ -25,5 +25,5 @@ func init() {
}
func registerREST() {
- roa.RegisterServent(&BrokerController{})
+ roa.RegisterServant(&AdminServiceControllerV4{})
}
diff --git a/server/govern/govern_suite_test.go b/server/admin/admin_suite_test.go
similarity index 76%
copy from server/govern/govern_suite_test.go
copy to server/admin/admin_suite_test.go
index 8a71d2e..d2444ea 100644
--- a/server/govern/govern_suite_test.go
+++ b/server/admin/admin_suite_test.go
@@ -14,16 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package govern_test
+package admin
import (
"github.com/apache/incubator-servicecomb-service-center/pkg/util"
- pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
- "github.com/apache/incubator-servicecomb-service-center/server/govern"
_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/quota/buildin"
_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/registry/etcd"
_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/uuid/buildin"
- "github.com/apache/incubator-servicecomb-service-center/server/service"
. "github.com/onsi/ginkgo"
"github.com/onsi/ginkgo/reporters"
. "github.com/onsi/gomega"
@@ -31,20 +28,14 @@ import (
"testing"
)
-func TestGovern(t *testing.T) {
+func TestAdmin(t *testing.T) {
RegisterFailHandler(Fail)
junitReporter := reporters.NewJUnitReporter("model.junit.xml")
RunSpecsWithDefaultAndCustomReporters(t, "model Suite", []Reporter{junitReporter})
}
-var serviceResource pb.ServiceCtrlServer
-var instanceResource pb.SerivceInstanceCtrlServerEx
-var governService pb.GovernServiceCtrlServerEx
-
var _ = BeforeSuite(func() {
//init plugin
- serviceResource, instanceResource = service.AssembleResources()
- governService = govern.GovernServiceAPI
})
func getContext() context.Context {
diff --git a/main.go b/server/admin/controller_v4.go
similarity index 54%
copy from main.go
copy to server/admin/controller_v4.go
index 3d7ac97..5fd786a 100644
--- a/main.go
+++ b/server/admin/controller_v4.go
@@ -14,22 +14,33 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package main
+package admin
-// plugins
-import _ "github.com/apache/incubator-servicecomb-service-center/server/bootstrap"
import (
- "github.com/apache/incubator-servicecomb-service-center/pkg/util"
- "github.com/apache/incubator-servicecomb-service-center/server"
- "github.com/apache/incubator-servicecomb-service-center/server/core/backend"
+ "net/http"
+
+ "github.com/apache/incubator-servicecomb-service-center/pkg/rest"
+ "github.com/apache/incubator-servicecomb-service-center/server/admin/model"
+ "github.com/apache/incubator-servicecomb-service-center/server/rest/controller"
)
-func main() {
- server.Run()
+// AdminService 治理相关接口服务
+type AdminServiceControllerV4 struct {
+}
- util.GoCloseAndWait()
+// URLPatterns 路由
+func (ctrl *AdminServiceControllerV4) URLPatterns() []rest.Route {
+ return []rest.Route{
+ {rest.HTTP_METHOD_GET, "/v4/:project/admin/dump", ctrl.Dump},
+ }
+}
- backend.Registry().Close()
+func (ctrl *AdminServiceControllerV4) Dump(w http.ResponseWriter, r *http.Request) {
+ request := &model.DumpRequest{}
+ ctx := r.Context()
+ resp, _ := AdminServiceAPI.Dump(ctx, request)
- util.Logger().Warn("service center exited", nil)
+ respInternal := resp.Response
+ resp.Response = nil
+ controller.WriteResponse(w, respInternal, resp)
}
diff --git a/server/admin/model/dump.go b/server/admin/model/dump.go
new file mode 100644
index 0000000..fb91411
--- /dev/null
+++ b/server/admin/model/dump.go
@@ -0,0 +1,185 @@
+/*
+ * 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 model
+
+import (
+ pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
+)
+
+type Getter interface {
+ ForEach(i func(i int, v *KV))
+}
+
+type Setter interface {
+ SetValue(v *KV)
+}
+
+type MicroserviceSlice []*Microservice
+type MicroserviceIndexSlice []*MicroserviceIndex
+type MicroserviceAliasSlice []*MicroserviceAlias
+type TagSlice []*Tag
+type MicroServiceRuleSlice []*MicroServiceRule
+type MicroServiceDependencyRuleSlice []*MicroServiceDependencyRule
+type SummarySlice []*Summary
+type InstanceSlice []*Instance
+
+func (s *MicroserviceSlice) ForEach(f func(i int, v *KV)) {
+ for i, v := range *s {
+ v.KV.Value = v.Value
+ f(i, v.KV)
+ }
+}
+func (s *MicroserviceIndexSlice) ForEach(f func(i int, v *KV)) {
+ for i, v := range *s {
+ v.KV.Value = v.Value
+ f(i, v.KV)
+ }
+}
+func (s *MicroserviceAliasSlice) ForEach(f func(i int, v *KV)) {
+ for i, v := range *s {
+ v.KV.Value = v.Value
+ f(i, v.KV)
+ }
+}
+func (s *TagSlice) ForEach(f func(i int, v *KV)) {
+ for i, v := range *s {
+ v.KV.Value = v.Value
+ f(i, v.KV)
+ }
+}
+func (s *MicroServiceRuleSlice) ForEach(f func(i int, v *KV)) {
+ for i, v := range *s {
+ v.KV.Value = v.Value
+ f(i, v.KV)
+ }
+}
+func (s *MicroServiceDependencyRuleSlice) ForEach(f func(i int, v *KV)) {
+ for i, v := range *s {
+ v.KV.Value = v.Value
+ f(i, v.KV)
+ }
+}
+func (s *SummarySlice) ForEach(f func(i int, v *KV)) {
+ for i, v := range *s {
+ v.KV.Value = v.Value
+ f(i, v.KV)
+ }
+}
+func (s *InstanceSlice) ForEach(f func(i int, v *KV)) {
+ for i, v := range *s {
+ v.KV.Value = v.Value
+ f(i, v.KV)
+ }
+}
+
+func (s *MicroserviceSlice) SetValue(v *KV) { *s = append(*s, NewMicroservice(v)) }
+func (s *MicroserviceIndexSlice) SetValue(v *KV) { *s = append(*s, NewMicroserviceIndex(v)) }
+func (s *MicroserviceAliasSlice) SetValue(v *KV) { *s = append(*s, NewMicroserviceAlias(v)) }
+func (s *TagSlice) SetValue(v *KV) { *s = append(*s, NewTag(v)) }
+func (s *MicroServiceRuleSlice) SetValue(v *KV) { *s = append(*s, NewMicroServiceRule(v)) }
+func (s *MicroServiceDependencyRuleSlice) SetValue(v *KV) {
+ *s = append(*s, NewMicroServiceDependencyRule(v))
+}
+func (s *SummarySlice) SetValue(v *KV) { *s = append(*s, NewSummary(v)) }
+func (s *InstanceSlice) SetValue(v *KV) { *s = append(*s, NewInstance(v)) }
+
+func NewMicroservice(kv *KV) *Microservice {
+ return &Microservice{kv, kv.Value.(*pb.MicroService)}
+}
+func NewMicroserviceIndex(kv *KV) *MicroserviceIndex {
+ return &MicroserviceIndex{kv, kv.Value.(string)}
+}
+func NewMicroserviceAlias(kv *KV) *MicroserviceAlias {
+ return &MicroserviceAlias{kv, kv.Value.(string)}
+}
+func NewTag(kv *KV) *Tag { return &Tag{kv, kv.Value.(map[string]string)} }
+func NewMicroServiceRule(kv *KV) *MicroServiceRule {
+ return &MicroServiceRule{kv, kv.Value.(*pb.ServiceRule)}
+}
+func NewMicroServiceDependencyRule(kv *KV) *MicroServiceDependencyRule {
+ return &MicroServiceDependencyRule{kv, kv.Value.(*pb.MicroServiceDependency)}
+}
+func NewSummary(kv *KV) *Summary { return &Summary{kv, kv.Value.(string)} }
+func NewInstance(kv *KV) *Instance {
+ return &Instance{kv, kv.Value.(*pb.MicroServiceInstance)}
+}
+
+type Cache struct {
+ Microservices MicroserviceSlice `json:"services,omitempty"`
+ Indexes MicroserviceIndexSlice `json:"serviceIndexes,omitempty"`
+ Aliases MicroserviceAliasSlice `json:"serviceAliases,omitempty"`
+ Tags TagSlice `json:"serviceTags,omitempty"`
+ Rules MicroServiceRuleSlice `json:"serviceRules,omitempty"`
+ DependencyRules MicroServiceDependencyRuleSlice `json:"dependencyRules,omitempty"`
+ Summaries SummarySlice `json:"summaries,omitempty"`
+ Instances InstanceSlice `json:"instances,omitempty"`
+}
+
+type KV struct {
+ Key string `json:"key"`
+ Rev int64 `json:"rev"`
+ Value interface{} `json:"-"`
+}
+
+type Microservice struct {
+ *KV
+ Value *pb.MicroService `json:"value,omitempty"`
+}
+
+type MicroserviceIndex struct {
+ *KV
+ Value string `json:"value,omitempty"`
+}
+
+type MicroserviceAlias struct {
+ *KV
+ Value string `json:"value,omitempty"`
+}
+
+type MicroServiceDependencyRule struct {
+ *KV
+ Value *pb.MicroServiceDependency `json:"value,omitempty"`
+}
+
+type MicroServiceRule struct {
+ *KV
+ Value *pb.ServiceRule `json:"value,omitempty"`
+}
+
+type Summary struct {
+ *KV
+ Value string `json:"value,omitempty"`
+}
+
+type Tag struct {
+ *KV
+ Value map[string]string `json:"value,omitempty"`
+}
+
+type Instance struct {
+ *KV
+ Value *pb.MicroServiceInstance `json:"value,omitempty"`
+}
+
+type DumpRequest struct {
+ Options []string
+}
+
+type DumpResponse struct {
+ Response *pb.Response `json:"response,omitempty"`
+ Cache *Cache `json:"cache,omitempty"`
+}
diff --git a/server/admin/service.go b/server/admin/service.go
new file mode 100644
index 0000000..166a057
--- /dev/null
+++ b/server/admin/service.go
@@ -0,0 +1,71 @@
+/*
+ * 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 admin
+
+import (
+ "github.com/apache/incubator-servicecomb-service-center/pkg/util"
+ "github.com/apache/incubator-servicecomb-service-center/server/admin/model"
+ "github.com/apache/incubator-servicecomb-service-center/server/core"
+ "github.com/apache/incubator-servicecomb-service-center/server/core/backend"
+ pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
+ scerr "github.com/apache/incubator-servicecomb-service-center/server/error"
+ "golang.org/x/net/context"
+)
+
+var AdminServiceAPI = &AdminService{}
+
+type AdminService struct {
+}
+
+func (service *AdminService) Dump(ctx context.Context, in *model.DumpRequest) (*model.DumpResponse, error) {
+
+ domainProject := util.ParseDomainProject(ctx)
+ var cache model.Cache
+
+ if !core.IsDefaultDomainProject(domainProject) {
+ return &model.DumpResponse{
+ Response: pb.CreateResponse(scerr.ErrForbidden, "Required admin permission"),
+ }, nil
+ }
+
+ service.dumpAll(ctx, &cache)
+
+ return &model.DumpResponse{
+ Response: pb.CreateResponse(pb.Response_SUCCESS, "Admin dump successfully"),
+ Cache: &cache,
+ }, nil
+}
+
+func (service *AdminService) dumpAll(ctx context.Context, cache *model.Cache) {
+ util.NewGo(ctx, util.PoolConfigure().Workers(2)).
+ Do(func(_ context.Context) { setValue(backend.Store().Service(), &cache.Microservices) }).
+ Do(func(_ context.Context) { setValue(backend.Store().ServiceIndex(), &cache.Indexes) }).
+ Do(func(_ context.Context) { setValue(backend.Store().ServiceAlias(), &cache.Aliases) }).
+ Do(func(_ context.Context) { setValue(backend.Store().ServiceTag(), &cache.Tags) }).
+ Do(func(_ context.Context) { setValue(backend.Store().Rule(), &cache.Rules) }).
+ Do(func(_ context.Context) { setValue(backend.Store().DependencyRule(), &cache.DependencyRules) }).
+ Do(func(_ context.Context) { setValue(backend.Store().SchemaSummary(), &cache.Summaries) }).
+ Do(func(_ context.Context) { setValue(backend.Store().Instance(), &cache.Instances) }).
+ Done()
+}
+
+func setValue(e backend.Entity, setter model.Setter) {
+ e.Cache().ForEach(func(k string, kv *backend.KeyValue) (next bool) {
+ setter.SetValue(&model.KV{Key: k, Rev: kv.ModRevision, Value: kv.Value})
+ return true
+ })
+}
diff --git a/server/broker/broker_suite_test.go b/server/admin/service_test.go
similarity index 53%
copy from server/broker/broker_suite_test.go
copy to server/admin/service_test.go
index 8bc652e..ff32bdf 100644
--- a/server/broker/broker_suite_test.go
+++ b/server/admin/service_test.go
@@ -14,32 +14,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package broker
+package admin
import (
+ "github.com/apache/incubator-servicecomb-service-center/pkg/util"
+ "github.com/apache/incubator-servicecomb-service-center/server/admin/model"
pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
- _ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/quota/buildin"
- _ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/registry/etcd"
- _ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/tracing/buildin"
- _ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/uuid/buildin"
- "github.com/apache/incubator-servicecomb-service-center/server/service"
+ scerr "github.com/apache/incubator-servicecomb-service-center/server/error"
. "github.com/onsi/ginkgo"
- "github.com/onsi/ginkgo/reporters"
. "github.com/onsi/gomega"
- "testing"
+ "golang.org/x/net/context"
)
-var serviceResource pb.ServiceCtrlServer
-var instanceResource pb.SerivceInstanceCtrlServerEx
-var brokerResource = BrokerServiceAPI
-
-var _ = BeforeSuite(func() {
- //init plugin
- serviceResource, instanceResource = service.AssembleResources()
+var _ = Describe("'Admin' service", func() {
+ Describe("execute 'dump' operation", func() {
+ Context("when get all", func() {
+ It("should be passed", func() {
+ resp, err := AdminServiceAPI.Dump(getContext(), &model.DumpRequest{})
+ Expect(err).To(BeNil())
+ Expect(resp.Response.Code).To(Equal(pb.Response_SUCCESS))
+ })
+ })
+ Context("when get by domain project", func() {
+ It("should be passed", func() {
+ resp, err := AdminServiceAPI.Dump(
+ util.SetDomainProject(context.Background(), "x", "x"),
+ &model.DumpRequest{})
+ Expect(err).To(BeNil())
+ Expect(resp.Response.Code).To(Equal(scerr.ErrForbidden))
+ })
+ })
+ })
})
-
-func TestBroker(t *testing.T) {
- RegisterFailHandler(Fail)
- junitReporter := reporters.NewJUnitReporter("model.junit.xml")
- RunSpecsWithDefaultAndCustomReporters(t, "model Suite", []Reporter{junitReporter})
-}
diff --git a/server/api.go b/server/api.go
index f606fee..c694535 100644
--- a/server/api.go
+++ b/server/api.go
@@ -27,6 +27,7 @@ import (
"github.com/apache/incubator-servicecomb-service-center/server/rpc"
"github.com/apache/incubator-servicecomb-service-center/server/service"
"golang.org/x/net/context"
+ "strconv"
"time"
)
@@ -55,7 +56,7 @@ func (t APIType) String() string {
case REST:
return "rest"
default:
- return fmt.Sprintf("SCHEME%d", t)
+ return "SCHEME" + strconv.Itoa(int(t))
}
}
@@ -215,7 +216,7 @@ func (s *APIServer) startRESTServer() (err error) {
if err != nil {
return
}
- util.Logger().Infof("Local listen address: %s, host: %s", addr, s.HostName)
+ util.Logger().Infof("listen address: %s://%s, host: %s.", REST, addr, s.HostName)
s.goroutine.Do(func(_ context.Context) {
err := s.restSrv.Serve()
@@ -238,7 +239,7 @@ func (s *APIServer) startRPCServer() (err error) {
if err != nil {
return
}
- util.Logger().Infof("Local listen address: %s, host: %s.", addr, s.HostName)
+ util.Logger().Infof("listen address: %s://%s, host: %s.", RPC, addr, s.HostName)
s.goroutine.Do(func(_ context.Context) {
err := s.rpcSrv.Serve()
@@ -279,10 +280,11 @@ func (s *APIServer) Start() {
s.err <- err
return
}
-
// 心跳
s.startHeartBeatService()
+ ReportScInstance()
+
util.Logger().Info("api server is ready")
}
diff --git a/server/bootstrap/bootstrap.go b/server/bootstrap/bootstrap.go
index 184cb6d..f0efb35 100644
--- a/server/bootstrap/bootstrap.go
+++ b/server/bootstrap/bootstrap.go
@@ -16,8 +16,6 @@
*/
package bootstrap
-import _ "github.com/apache/incubator-servicecomb-service-center/server/core" // initialize
-
// rest
import _ "github.com/apache/incubator-servicecomb-service-center/server/rest/controller/v3"
import _ "github.com/apache/incubator-servicecomb-service-center/server/rest/controller/v4"
@@ -51,6 +49,9 @@ import _ "github.com/apache/incubator-servicecomb-service-center/server/govern"
// module 'broker'
import _ "github.com/apache/incubator-servicecomb-service-center/server/broker"
+// module 'admin'
+import _ "github.com/apache/incubator-servicecomb-service-center/server/admin"
+
// metrics
import _ "github.com/apache/incubator-servicecomb-service-center/server/metric"
diff --git a/server/broker/broker.go b/server/broker/broker.go
index fc807be..54840ae 100644
--- a/server/broker/broker.go
+++ b/server/broker/broker.go
@@ -25,5 +25,5 @@ func init() {
}
func registerREST() {
- roa.RegisterServent(&BrokerController{})
+ roa.RegisterServant(&BrokerController{})
}
diff --git a/server/broker/broker_suite_test.go b/server/broker/broker_suite_test.go
index 8bc652e..2bdfa72 100644
--- a/server/broker/broker_suite_test.go
+++ b/server/broker/broker_suite_test.go
@@ -17,7 +17,7 @@
package broker
import (
- pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
+ "github.com/apache/incubator-servicecomb-service-center/server/core"
_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/quota/buildin"
_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/registry/etcd"
_ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/tracing/buildin"
@@ -29,13 +29,12 @@ import (
"testing"
)
-var serviceResource pb.ServiceCtrlServer
-var instanceResource pb.SerivceInstanceCtrlServerEx
var brokerResource = BrokerServiceAPI
var _ = BeforeSuite(func() {
//init plugin
- serviceResource, instanceResource = service.AssembleResources()
+ core.ServerInfo.Config.EnableCache = false
+ core.ServiceAPI, core.InstanceAPI = service.AssembleResources()
})
func TestBroker(t *testing.T) {
diff --git a/server/broker/broker.pb.go b/server/broker/brokerpb/broker.pb.go
similarity index 99%
rename from server/broker/broker.pb.go
rename to server/broker/brokerpb/broker.pb.go
index c2709cd..d61f9d8 100644
--- a/server/broker/broker.pb.go
+++ b/server/broker/brokerpb/broker.pb.go
@@ -49,7 +49,7 @@ It has these top-level messages:
BrokerAPIInfoEntry
BrokerHomeResponse
*/
-package broker
+package brokerpb
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
diff --git a/server/broker/broker.proto b/server/broker/brokerpb/broker.proto
similarity index 100%
rename from server/broker/broker.proto
rename to server/broker/brokerpb/broker.proto
diff --git a/server/broker/controller.go b/server/broker/controller.go
index 05101f0..dc64522 100644
--- a/server/broker/controller.go
+++ b/server/broker/controller.go
@@ -23,6 +23,7 @@ import (
"strconv"
"github.com/apache/incubator-servicecomb-service-center/pkg/rest"
+ "github.com/apache/incubator-servicecomb-service-center/server/broker/brokerpb"
scerr "github.com/apache/incubator-servicecomb-service-center/server/error"
"github.com/apache/incubator-servicecomb-service-center/server/rest/controller"
)
@@ -60,7 +61,7 @@ func (brokerService *BrokerController) URLPatterns() []rest.Route {
}
func (brokerService *BrokerController) GetHome(w http.ResponseWriter, r *http.Request) {
- request := &BaseBrokerRequest{
+ request := &brokerpb.BaseBrokerRequest{
HostAddress: r.Host,
Scheme: getScheme(r),
}
@@ -79,7 +80,7 @@ func (*BrokerController) PublishPact(w http.ResponseWriter, r *http.Request) {
return
}
query := r.URL.Query()
- request := &PublishPactRequest{
+ request := &brokerpb.PublishPactRequest{
ProviderId: query.Get(":providerId"),
ConsumerId: query.Get(":consumerId"),
Version: query.Get(":number"),
@@ -95,9 +96,9 @@ func (*BrokerController) PublishPact(w http.ResponseWriter, r *http.Request) {
}
func (*BrokerController) GetAllProviderPacts(w http.ResponseWriter, r *http.Request) {
- request := &GetAllProviderPactsRequest{
+ request := &brokerpb.GetAllProviderPactsRequest{
ProviderId: r.URL.Query().Get(":providerId"),
- BaseUrl: &BaseBrokerRequest{
+ BaseUrl: &brokerpb.BaseBrokerRequest{
HostAddress: r.Host,
Scheme: getScheme(r),
},
@@ -115,11 +116,11 @@ func (*BrokerController) GetAllProviderPacts(w http.ResponseWriter, r *http.Requ
func (*BrokerController) GetPactsOfProvider(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
- request := &GetProviderConsumerVersionPactRequest{
+ request := &brokerpb.GetProviderConsumerVersionPactRequest{
ProviderId: query.Get(":providerId"),
ConsumerId: query.Get(":consumerId"),
Version: query.Get(":number"),
- BaseUrl: &BaseBrokerRequest{
+ BaseUrl: &brokerpb.BaseBrokerRequest{
HostAddress: r.Host,
Scheme: getScheme(r),
},
@@ -133,7 +134,7 @@ func (*BrokerController) GetPactsOfProvider(w http.ResponseWriter, r *http.Reque
}
func (*BrokerController) DeletePacts(w http.ResponseWriter, r *http.Request) {
- resp, _ := BrokerServiceAPI.DeletePacts(r.Context(), &BaseBrokerRequest{
+ resp, _ := BrokerServiceAPI.DeletePacts(r.Context(), &brokerpb.BaseBrokerRequest{
HostAddress: r.Host,
Scheme: getScheme(r),
})
@@ -147,7 +148,7 @@ func (*BrokerController) PublishVerificationResults(w http.ResponseWriter, r *ht
controller.WriteError(w, scerr.ErrInvalidParams, err.Error())
return
}
- request := &PublishVerificationRequest{}
+ request := &brokerpb.PublishVerificationRequest{}
err = json.Unmarshal(requestBody, request)
if err != nil {
PactLogger.Error("Unmarshal error", err)
@@ -175,7 +176,7 @@ func (*BrokerController) PublishVerificationResults(w http.ResponseWriter, r *ht
}
func (*BrokerController) RetrieveVerificationResults(w http.ResponseWriter, r *http.Request) {
- request := &RetrieveVerificationRequest{}
+ request := &brokerpb.RetrieveVerificationRequest{}
query := r.URL.Query()
request.ConsumerId = query.Get(":consumerId")
request.ConsumerVersion = query.Get(":consumerVersion")
diff --git a/server/broker/broker.go b/server/broker/controller_test.go
similarity index 60%
copy from server/broker/broker.go
copy to server/broker/controller_test.go
index fc807be..fe42bf4 100644
--- a/server/broker/broker.go
+++ b/server/broker/controller_test.go
@@ -17,13 +17,33 @@
package broker
import (
- roa "github.com/apache/incubator-servicecomb-service-center/pkg/rest"
+ "bytes"
+ "net/http"
+ "net/http/httptest"
+ "testing"
)
-func init() {
- registerREST()
+var (
+ ctrl = &BrokerController{}
+ num int
+)
+
+type mockBrokerHandler struct {
}
-func registerREST() {
- roa.RegisterServent(&BrokerController{})
+func (b *mockBrokerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ route := ctrl.URLPatterns()[num]
+ r.Method = route.Method
+ r.URL.RawQuery = ":sha=1"
+ route.Func(w, r)
+ num++
+}
+
+func TestBrokerController_GetHome(t *testing.T) {
+ svr := httptest.NewServer(&mockBrokerHandler{})
+ defer svr.Close()
+
+ for range ctrl.URLPatterns() {
+ http.Post(svr.URL, "application/json", bytes.NewBuffer([]byte("{}")))
+ }
}
diff --git a/server/broker/service.go b/server/broker/service.go
index c36cb3e..ec0a96a 100644
--- a/server/broker/service.go
+++ b/server/broker/service.go
@@ -19,13 +19,13 @@ package broker
import (
"crypto/sha1"
"encoding/json"
- "fmt"
"math"
"strconv"
"strings"
"time"
"github.com/apache/incubator-servicecomb-service-center/pkg/util"
+ "github.com/apache/incubator-servicecomb-service-center/server/broker/brokerpb"
apt "github.com/apache/incubator-servicecomb-service-center/server/core"
pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
scerr "github.com/apache/incubator-servicecomb-service-center/server/error"
@@ -40,11 +40,11 @@ type BrokerService struct {
}
func (*BrokerService) GetBrokerHome(ctx context.Context,
- in *BaseBrokerRequest) (*BrokerHomeResponse, error) {
+ in *brokerpb.BaseBrokerRequest) (*brokerpb.BrokerHomeResponse, error) {
if in == nil || len(in.HostAddress) == 0 {
PactLogger.Errorf(nil, "Get Participant versions request failed: invalid params.")
- return &BrokerHomeResponse{
+ return &brokerpb.BrokerHomeResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."),
}, nil
}
@@ -53,15 +53,18 @@ func (*BrokerService) GetBrokerHome(ctx context.Context,
}
func (*BrokerService) GetPactsOfProvider(ctx context.Context,
- in *GetProviderConsumerVersionPactRequest) (*GetProviderConsumerVersionPactResponse, error) {
+ in *brokerpb.GetProviderConsumerVersionPactRequest) (*brokerpb.GetProviderConsumerVersionPactResponse, error) {
PactLogger.Infof("GetPactsOfProvider: (%s, %s, %s)\n",
in.ProviderId, in.ConsumerId, in.Version)
resp, pactId, err := RetrieveProviderConsumerPact(ctx, in)
if err != nil || resp.GetPact() == nil || pactId == -1 {
- PactLogger.Errorf(nil, "Get pacts of provider failed: %s\n",
- resp.Response.Message)
- return &GetProviderConsumerVersionPactResponse{
+ var message string
+ if resp != nil {
+ message = resp.Response.Message
+ }
+ PactLogger.Errorf(err, "Get pacts of provider failed: %s\n", message)
+ return &brokerpb.GetProviderConsumerVersionPactResponse{
Response: resp.GetResponse(),
}, err
}
@@ -70,7 +73,7 @@ func (*BrokerService) GetPactsOfProvider(ctx context.Context,
BROKER_PUBLISH_VERIFICATION_URL,
strings.NewReplacer(":providerId", in.ProviderId,
":consumerId", in.ConsumerId,
- ":pact", fmt.Sprint(pactId)))
+ ":pact", strconv.FormatInt(int64(pactId), 10)))
links := ",\"_links\": {" +
"\"pb:publish-verification-results\": {" +
@@ -85,7 +88,7 @@ func (*BrokerService) GetPactsOfProvider(ctx context.Context,
sliceOfResp := pactBytes[0 : len(pactBytes)-2]
finalBytes := append(sliceOfResp, linksBytes...)
- return &GetProviderConsumerVersionPactResponse{
+ return &brokerpb.GetProviderConsumerVersionPactResponse{
Response: pb.CreateResponse(pb.Response_SUCCESS, "Success."),
Pact: finalBytes,
}, nil
@@ -94,7 +97,7 @@ func (*BrokerService) GetPactsOfProvider(ctx context.Context,
}
func (*BrokerService) DeletePacts(ctx context.Context,
- in *BaseBrokerRequest) (*pb.Response, error) {
+ in *brokerpb.BaseBrokerRequest) (*pb.Response, error) {
resp, err := DeletePactData(ctx, in)
@@ -102,10 +105,10 @@ func (*BrokerService) DeletePacts(ctx context.Context,
}
func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
- in *GetAllProviderPactsRequest) (*GetAllProviderPactsResponse, error) {
+ in *brokerpb.GetAllProviderPactsRequest) (*brokerpb.GetAllProviderPactsResponse, error) {
if in == nil || len(in.ProviderId) == 0 {
PactLogger.Errorf(nil, "all provider pact retrieve request failed: invalid params.")
- return &GetAllProviderPactsResponse{
+ return &brokerpb.GetAllProviderPactsResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."),
}, nil
}
@@ -114,13 +117,13 @@ func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
provider, err := serviceUtil.GetService(ctx, tenant, in.ProviderId)
if err != nil {
PactLogger.Errorf(err, "all provider pact retrieve failed, providerId is %s: query provider failed.", in.ProviderId)
- return &GetAllProviderPactsResponse{
+ return &brokerpb.GetAllProviderPactsResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query provider failed."),
}, err
}
if provider == nil {
PactLogger.Errorf(nil, "all provider pact retrieve failed, providerId is %s: provider not exist.", in.ProviderId)
- return &GetAllProviderPactsResponse{
+ return &brokerpb.GetAllProviderPactsResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider does not exist."),
}, nil
}
@@ -129,7 +132,7 @@ func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
providerParticipant, err := GetParticipant(ctx, tenant, provider.AppId, provider.ServiceName)
if err != nil || providerParticipant == nil {
PactLogger.Errorf(nil, "all provider pact retrieve failed, provider participant cannot be searched.", in.ProviderId)
- return &GetAllProviderPactsResponse{
+ return &brokerpb.GetAllProviderPactsResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider participant cannot be searched."),
}, err
}
@@ -148,9 +151,9 @@ func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
return nil, nil
}
// Store versions in a map
- versionObjects := make(map[int32]Version)
+ versionObjects := make(map[int32]brokerpb.Version)
for i := 0; i < len(versions.Kvs); i++ {
- version := &Version{}
+ version := &brokerpb.Version{}
err = json.Unmarshal(versions.Kvs[i].Value.([]byte), version)
if err != nil {
return nil, err
@@ -171,9 +174,9 @@ func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
PactLogger.Info("[RetrieveProviderPacts] No pact version found, sorry")
return nil, nil
}
- participantToVersionObj := make(map[int32]Version)
+ participantToVersionObj := make(map[int32]brokerpb.Version)
for i := 0; i < len(pactVersions.Kvs); i++ {
- pactVersion := &PactVersion{}
+ pactVersion := &brokerpb.PactVersion{}
err = json.Unmarshal(pactVersions.Kvs[i].Value.([]byte), pactVersion)
if err != nil {
return nil, err
@@ -203,9 +206,9 @@ func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
if len(participants.Kvs) == 0 {
return nil, nil
}
- consumerInfoArr := make([]*ConsumerInfo, 0)
+ consumerInfoArr := make([]*brokerpb.ConsumerInfo, 0)
for i := 0; i < len(participants.Kvs); i++ {
- participant := &Participant{}
+ participant := &brokerpb.Participant{}
err = json.Unmarshal(participants.Kvs[i].Value.([]byte), participant)
if err != nil {
return nil, err
@@ -232,13 +235,13 @@ func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
":consumerId", consumerId,
":number", consumerVersion))
- consumerInfo := &ConsumerInfo{
+ consumerInfo := &brokerpb.ConsumerInfo{
Href: urlValue,
Name: consumerId,
}
consumerInfoArr = append(consumerInfoArr, consumerInfo)
}
- links := &Links{
+ links := &brokerpb.Links{
Pacts: consumerInfoArr,
}
resJson, err := json.Marshal(links)
@@ -246,7 +249,7 @@ func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
return nil, err
}
PactLogger.Infof("Json : %s", string(resJson))
- response := &GetAllProviderPactsResponse{
+ response := &brokerpb.GetAllProviderPactsResponse{
Response: pb.CreateResponse(pb.Response_SUCCESS, "retrieve provider pact info succeeded."),
XLinks: links,
}
@@ -254,11 +257,11 @@ func (*BrokerService) RetrieveProviderPacts(ctx context.Context,
}
func (*BrokerService) GetAllProviderPacts(ctx context.Context,
- in *GetAllProviderPactsRequest) (*GetAllProviderPactsResponse, error) {
+ in *brokerpb.GetAllProviderPactsRequest) (*brokerpb.GetAllProviderPactsResponse, error) {
if in == nil || len(in.ProviderId) == 0 {
PactLogger.Errorf(nil, "all provider pact retrieve request failed: invalid params.")
- return &GetAllProviderPactsResponse{
+ return &brokerpb.GetAllProviderPactsResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."),
}, nil
}
@@ -267,13 +270,13 @@ func (*BrokerService) GetAllProviderPacts(ctx context.Context,
provider, err := serviceUtil.GetService(ctx, tenant, in.ProviderId)
if err != nil {
PactLogger.Errorf(err, "all provider pact retrieve failed, providerId is %s: query provider failed.", in.ProviderId)
- return &GetAllProviderPactsResponse{
+ return &brokerpb.GetAllProviderPactsResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query provider failed."),
}, err
}
if provider == nil {
PactLogger.Errorf(nil, "all provider pact retrieve failed, providerId is %s: provider not exist.", in.ProviderId)
- return &GetAllProviderPactsResponse{
+ return &brokerpb.GetAllProviderPactsResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider does not exist."),
}, nil
}
@@ -282,7 +285,7 @@ func (*BrokerService) GetAllProviderPacts(ctx context.Context,
providerParticipant, err := GetParticipant(ctx, tenant, provider.AppId, provider.ServiceName)
if err != nil || providerParticipant == nil {
PactLogger.Errorf(nil, "all provider pact retrieve failed, provider participant cannot be searched.", in.ProviderId)
- return &GetAllProviderPactsResponse{
+ return &brokerpb.GetAllProviderPactsResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider participant cannot be searched."),
}, err
}
@@ -301,9 +304,9 @@ func (*BrokerService) GetAllProviderPacts(ctx context.Context,
return nil, nil
}
// Store versions in a map
- versionObjects := make(map[int32]Version)
+ versionObjects := make(map[int32]brokerpb.Version)
for i := 0; i < len(versions.Kvs); i++ {
- version := &Version{}
+ version := &brokerpb.Version{}
err = json.Unmarshal(versions.Kvs[i].Value.([]byte), version)
if err != nil {
return nil, err
@@ -324,9 +327,9 @@ func (*BrokerService) GetAllProviderPacts(ctx context.Context,
PactLogger.Info("[RetrieveProviderPacts] No pact version found, sorry")
return nil, nil
}
- participantToVersionObj := make(map[int32]Version)
+ participantToVersionObj := make(map[int32]brokerpb.Version)
for i := 0; i < len(pactVersions.Kvs); i++ {
- pactVersion := &PactVersion{}
+ pactVersion := &brokerpb.PactVersion{}
err = json.Unmarshal(pactVersions.Kvs[i].Value.([]byte), pactVersion)
if err != nil {
return nil, err
@@ -356,9 +359,9 @@ func (*BrokerService) GetAllProviderPacts(ctx context.Context,
if len(participants.Kvs) == 0 {
return nil, nil
}
- consumerInfoArr := make([]*ConsumerInfo, 0)
+ consumerInfoArr := make([]*brokerpb.ConsumerInfo, 0)
for i := 0; i < len(participants.Kvs); i++ {
- participant := &Participant{}
+ participant := &brokerpb.Participant{}
err = json.Unmarshal(participants.Kvs[i].Value.([]byte), participant)
if err != nil {
return nil, err
@@ -385,13 +388,13 @@ func (*BrokerService) GetAllProviderPacts(ctx context.Context,
":consumerId", consumerId,
":number", consumerVersion))
- consumerInfo := &ConsumerInfo{
+ consumerInfo := &brokerpb.ConsumerInfo{
Href: urlValue,
Name: consumerId,
}
consumerInfoArr = append(consumerInfoArr, consumerInfo)
}
- links := &Links{
+ links := &brokerpb.Links{
Pacts: consumerInfoArr,
}
resJson, err := json.Marshal(links)
@@ -399,17 +402,17 @@ func (*BrokerService) GetAllProviderPacts(ctx context.Context,
return nil, err
}
PactLogger.Infof("Json : %s", string(resJson))
- response := &GetAllProviderPactsResponse{
+ response := &brokerpb.GetAllProviderPactsResponse{
Response: pb.CreateResponse(pb.Response_SUCCESS, "retrieve provider pact info succeeded."),
XLinks: links,
}
return response, nil
}
-func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *RetrieveVerificationRequest) (*RetrieveVerificationResponse, error) {
+func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *brokerpb.RetrieveVerificationRequest) (*brokerpb.RetrieveVerificationResponse, error) {
if in == nil || len(in.ConsumerId) == 0 || len(in.ConsumerVersion) == 0 {
PactLogger.Errorf(nil, "verification result retrieve request failed: invalid params.")
- return &RetrieveVerificationResponse{
+ return &brokerpb.RetrieveVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."),
}, nil
}
@@ -417,13 +420,13 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
consumer, err := serviceUtil.GetService(ctx, tenant, in.ConsumerId)
if err != nil {
PactLogger.Errorf(err, "verification result retrieve request failed, consumerId is %s: query consumer failed.", in.ConsumerId)
- return &RetrieveVerificationResponse{
+ return &brokerpb.RetrieveVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query consumer failed."),
}, err
}
if consumer == nil {
PactLogger.Errorf(nil, "verification result retrieve request failed, consumerId is %s: consumer not exist.", in.ConsumerId)
- return &RetrieveVerificationResponse{
+ return &brokerpb.RetrieveVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Consumer does not exist."),
}, nil
}
@@ -432,7 +435,7 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
consumerParticipant, err := GetParticipant(ctx, tenant, consumer.AppId, consumer.ServiceName)
if err != nil || consumerParticipant == nil {
PactLogger.Errorf(nil, "verification result retrieve request failed, consumer participant cannot be searched.", in.ConsumerId)
- return &RetrieveVerificationResponse{
+ return &brokerpb.RetrieveVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "consumer participant cannot be searched."),
}, err
}
@@ -441,7 +444,7 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
version, err := GetVersion(ctx, tenant, consumer.Version, consumerParticipant.Id)
if err != nil || version == nil {
PactLogger.Errorf(nil, "verification result retrieve request failed, version cannot be searched.")
- return &RetrieveVerificationResponse{
+ return &brokerpb.RetrieveVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "version cannot be searched."),
}, err
}
@@ -453,7 +456,7 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
if err != nil || len(pactVersions.Kvs) == 0 {
PactLogger.Errorf(nil, "verification result publish request failed, pact version cannot be searched.")
- return &RetrieveVerificationResponse{
+ return &brokerpb.RetrieveVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact version cannot be searched."),
}, err
}
@@ -463,13 +466,13 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
fails := make([]string, 0)
unknowns := make([]string, 0)
- verificationDetailsArr := make([]*VerificationDetail, 0)
+ verificationDetailsArr := make([]*brokerpb.VerificationDetail, 0)
for j := 0; j < len(pactVersions.Kvs); j++ {
- pactVersion := &PactVersion{}
+ pactVersion := &brokerpb.PactVersion{}
err = json.Unmarshal(pactVersions.Kvs[j].Value.([]byte), &pactVersion)
if err != nil {
PactLogger.Errorf(nil, "verification result retrieve request failed, pact version cannot be searched.")
- return &RetrieveVerificationResponse{
+ return &brokerpb.RetrieveVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact version cannot be searched."),
}, err
}
@@ -480,18 +483,18 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
if err != nil || len(verifications.Kvs) == 0 {
PactLogger.Errorf(nil, "verification result retrieve request failed, verification results cannot be searched.")
- return &RetrieveVerificationResponse{
+ return &brokerpb.RetrieveVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification results cannot be searched."),
}, err
}
lastNumber := int32(math.MinInt32)
- var lastVerificationResult *Verification
+ var lastVerificationResult *brokerpb.Verification
for i := 0; i < len(verifications.Kvs); i++ {
- verification := &Verification{}
+ verification := &brokerpb.Verification{}
err = json.Unmarshal(verifications.Kvs[i].Value.([]byte), &verification)
if err != nil {
PactLogger.Errorf(nil, "verification result retrieve request failed, verification result unmarshall error.")
- return &RetrieveVerificationResponse{
+ return &brokerpb.RetrieveVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result unmarshall error."),
}, err
}
@@ -502,7 +505,7 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
}
if lastVerificationResult == nil {
PactLogger.Errorf(nil, "verification result retrieve request failed, verification result cannot be found.")
- return &RetrieveVerificationResponse{
+ return &brokerpb.RetrieveVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result cannot be found."),
}, err
}
@@ -518,17 +521,17 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
if err != nil || len(participants.Kvs) == 0 {
PactLogger.Errorf(nil, "verification result retrieve request failed, provider participant cannot be searched.")
- return &RetrieveVerificationResponse{
+ return &brokerpb.RetrieveVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "provider participant cannot be searched."),
}, err
}
- var providerParticipant *Participant
+ var providerParticipant *brokerpb.Participant
for i := 0; i < len(participants.Kvs); i++ {
- participant := &Participant{}
+ participant := &brokerpb.Participant{}
err = json.Unmarshal(participants.Kvs[i].Value.([]byte), &participant)
if err != nil {
PactLogger.Errorf(nil, "verification result retrieve request failed, verification result unmarshall error.")
- return &RetrieveVerificationResponse{
+ return &brokerpb.RetrieveVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result unmarshall error."),
}, err
}
@@ -539,7 +542,7 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
}
if providerParticipant == nil {
PactLogger.Errorf(nil, "verification result retrieve request failed, verification result unmarshall error.")
- return &RetrieveVerificationResponse{
+ return &brokerpb.RetrieveVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result unmarshall error."),
}, err
}
@@ -552,12 +555,12 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
resp, err := apt.ServiceAPI.Exist(ctx, serviceFindReq)
if err != nil {
PactLogger.Errorf(nil, "verification result retrieve request failed, provider service cannot be found.")
- return &RetrieveVerificationResponse{
+ return &brokerpb.RetrieveVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "provider service cannot be found."),
}, err
}
providerName := resp.ServiceId
- verificationDetail := &VerificationDetail{
+ verificationDetail := &brokerpb.VerificationDetail{
ProviderName: providerName,
ProviderApplicationVersion: lastVerificationResult.ProviderVersion,
Success: lastVerificationResult.Success,
@@ -571,20 +574,20 @@ func (*BrokerService) RetrieveVerificationResults(ctx context.Context, in *Retri
}
overAllSuccess = overAllSuccess && verificationDetail.Success
}
- verificationDetails := &VerificationDetails{VerificationResults: verificationDetailsArr}
- verificationSummary := &VerificationSummary{Successful: successfuls, Failed: fails, Unknown: unknowns}
- verificationResult := &VerificationResult{Success: overAllSuccess, ProviderSummary: verificationSummary, XEmbedded: verificationDetails}
+ verificationDetails := &brokerpb.VerificationDetails{VerificationResults: verificationDetailsArr}
+ verificationSummary := &brokerpb.VerificationSummary{Successful: successfuls, Failed: fails, Unknown: unknowns}
+ verificationResult := &brokerpb.VerificationResult{Success: overAllSuccess, ProviderSummary: verificationSummary, XEmbedded: verificationDetails}
PactLogger.Infof("Verification result retrieved successfully ...")
- return &RetrieveVerificationResponse{
+ return &brokerpb.RetrieveVerificationResponse{
Response: pb.CreateResponse(pb.Response_SUCCESS, "Verification result retrieved successfully."),
Result: verificationResult,
}, nil
}
-func (*BrokerService) PublishVerificationResults(ctx context.Context, in *PublishVerificationRequest) (*PublishVerificationResponse, error) {
+func (*BrokerService) PublishVerificationResults(ctx context.Context, in *brokerpb.PublishVerificationRequest) (*brokerpb.PublishVerificationResponse, error) {
if in == nil || len(in.ProviderId) == 0 || len(in.ConsumerId) == 0 {
PactLogger.Errorf(nil, "verification result publish request failed: invalid params.")
- return &PublishVerificationResponse{
+ return &brokerpb.PublishVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."),
}, nil
}
@@ -592,13 +595,13 @@ func (*BrokerService) PublishVerificationResults(ctx context.Context, in *Publis
consumer, err := serviceUtil.GetService(ctx, tenant, in.ConsumerId)
if err != nil {
PactLogger.Errorf(err, "verification result publish request failed, consumerId is %s: query consumer failed.", in.ConsumerId)
- return &PublishVerificationResponse{
+ return &brokerpb.PublishVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query consumer failed."),
}, err
}
if consumer == nil {
PactLogger.Errorf(nil, "verification result publish request failed, consumerId is %s: consumer not exist.", in.ConsumerId)
- return &PublishVerificationResponse{
+ return &brokerpb.PublishVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Consumer does not exist."),
}, nil
}
@@ -607,7 +610,7 @@ func (*BrokerService) PublishVerificationResults(ctx context.Context, in *Publis
consumerParticipant, err := GetParticipant(ctx, tenant, consumer.AppId, consumer.ServiceName)
if err != nil || consumerParticipant == nil {
PactLogger.Errorf(nil, "verification result publish request failed, consumer participant cannot be searched.", in.ConsumerId)
- return &PublishVerificationResponse{
+ return &brokerpb.PublishVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "consumer participant cannot be searched."),
}, err
}
@@ -616,7 +619,7 @@ func (*BrokerService) PublishVerificationResults(ctx context.Context, in *Publis
version, err := GetVersion(ctx, tenant, consumer.Version, consumerParticipant.Id)
if err != nil || version == nil {
PactLogger.Errorf(nil, "verification result publish request failed, version cannot be searched.")
- return &PublishVerificationResponse{
+ return &brokerpb.PublishVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "version cannot be searched."),
}, err
}
@@ -628,17 +631,17 @@ func (*BrokerService) PublishVerificationResults(ctx context.Context, in *Publis
if err != nil || len(pacts.Kvs) == 0 {
PactLogger.Errorf(nil, "verification result publish request failed, pact cannot be searched.")
- return &PublishVerificationResponse{
+ return &brokerpb.PublishVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact cannot be searched."),
}, err
}
pactExists := false
for i := 0; i < len(pacts.Kvs); i++ {
- pact := &Pact{}
+ pact := &brokerpb.Pact{}
err = json.Unmarshal(pacts.Kvs[i].Value.([]byte), &pact)
if err != nil {
PactLogger.Errorf(nil, "verification result publish request failed, pact cannot be searched.")
- return &PublishVerificationResponse{
+ return &brokerpb.PublishVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact cannot be searched."),
}, err
}
@@ -648,14 +651,14 @@ func (*BrokerService) PublishVerificationResults(ctx context.Context, in *Publis
}
if pactExists == false {
PactLogger.Errorf(nil, "verification result publish request failed, pact does not exists.")
- return &PublishVerificationResponse{
+ return &brokerpb.PublishVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact does not exists."),
}, err
}
pactVersion, err := GetPactVersion(ctx, tenant, version.Id, in.PactId)
if err != nil || pactVersion == nil {
PactLogger.Errorf(nil, "verification result publish request failed, pact version cannot be searched.")
- return &PublishVerificationResponse{
+ return &brokerpb.PublishVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact version cannot be searched."),
}, err
}
@@ -667,18 +670,18 @@ func (*BrokerService) PublishVerificationResults(ctx context.Context, in *Publis
if err != nil {
PactLogger.Errorf(nil, "verification result publish request failed, verification result cannot be searched.")
- return &PublishVerificationResponse{
+ return &brokerpb.PublishVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result cannot be searched."),
}, err
}
lastNumber := int32(math.MinInt32)
if len(verifications.Kvs) != 0 {
for i := 0; i < len(verifications.Kvs); i++ {
- verification := &Verification{}
+ verification := &brokerpb.Verification{}
err = json.Unmarshal(verifications.Kvs[i].Value.([]byte), &verification)
if err != nil {
PactLogger.Errorf(nil, "verification result publish request failed, verification result unmarshall error.")
- return &PublishVerificationResponse{
+ return &brokerpb.PublishVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "verification result unmarshall error."),
}, err
}
@@ -695,7 +698,7 @@ func (*BrokerService) PublishVerificationResults(ctx context.Context, in *Publis
verificationDate := time.Now().Format(time.RFC3339)
verificationKey := GenerateBrokerVerificationKey(tenant, pactVersion.Id, lastNumber)
id, err := GetData(ctx, GetBrokerLatestVerificationIDKey())
- verification := &Verification{
+ verification := &brokerpb.Verification{
Id: int32(id) + 1,
Number: lastNumber,
PactVersionId: pactVersion.Id,
@@ -711,23 +714,23 @@ func (*BrokerService) PublishVerificationResults(ctx context.Context, in *Publis
PactLogger.Infof("Verification result inserted: (%d, %d, %d, %t, %s, %s, %s)",
verification.Id, verification.Number, verification.PactVersionId,
verification.Success, verification.ProviderVersion, verification.BuildUrl, verification.VerificationDate)
- verificationResponse := &VerificationDetail{
+ verificationResponse := &brokerpb.VerificationDetail{
ProviderName: in.ProviderId,
ProviderApplicationVersion: verification.ProviderVersion,
Success: verification.Success,
VerificationDate: verification.VerificationDate,
}
PactLogger.Infof("Verification result published successfully ...")
- return &PublishVerificationResponse{
+ return &brokerpb.PublishVerificationResponse{
Response: pb.CreateResponse(pb.Response_SUCCESS, "Verification result published successfully."),
Confirmation: verificationResponse,
}, nil
}
-func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (*PublishPactResponse, error) {
+func (*BrokerService) PublishPact(ctx context.Context, in *brokerpb.PublishPactRequest) (*brokerpb.PublishPactResponse, error) {
if in == nil || len(in.ProviderId) == 0 || len(in.ConsumerId) == 0 || len(in.Version) == 0 || len(in.Pact) == 0 {
PactLogger.Errorf(nil, "pact publish request failed: invalid params.")
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Request format invalid."),
}, nil
}
@@ -736,13 +739,13 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
provider, err := serviceUtil.GetService(ctx, tenant, in.ProviderId)
if err != nil {
PactLogger.Errorf(err, "pact publish failed, providerId is %s: query provider failed.", in.ProviderId)
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query provider failed."),
}, err
}
if provider == nil {
PactLogger.Errorf(nil, "pact publish failed, providerId is %s: provider not exist.", in.ProviderId)
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider does not exist."),
}, nil
}
@@ -750,13 +753,13 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
consumer, err := serviceUtil.GetService(ctx, tenant, in.ConsumerId)
if err != nil {
PactLogger.Errorf(err, "pact publish failed, consumerId is %s: query consumer failed.", in.ConsumerId)
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Query consumer failed."),
}, err
}
if consumer == nil {
PactLogger.Errorf(nil, "pact publish failed, consumerId is %s: consumer not exist.", in.ConsumerId)
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Consumer does not exist."),
}, nil
}
@@ -765,7 +768,7 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
if strings.Compare(consumer.GetVersion(), in.Version) != 0 {
util.Logger().Errorf(nil,
"pact publish failed, version (%s) does not exist for consmer", in.Version)
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Consumer Version does not exist."),
}, nil
}
@@ -776,13 +779,13 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
providerParticipant, err := GetParticipant(ctx, tenant, provider.AppId, provider.ServiceName)
if err != nil {
PactLogger.Errorf(nil, "pact publish failed, provider participant cannot be searched.", in.ProviderId)
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "Provider participant cannot be searched."),
}, err
}
if providerParticipant == nil {
id, err := GetData(ctx, GetBrokerLatestParticipantIDKey())
- providerParticipant = &Participant{Id: int32(id) + 1, AppId: provider.AppId, ServiceName: provider.ServiceName}
+ providerParticipant = &brokerpb.Participant{Id: int32(id) + 1, AppId: provider.AppId, ServiceName: provider.ServiceName}
response, err := CreateParticipant(PactLogger, ctx, providerParticipantKey, *providerParticipant)
if err != nil {
return response, err
@@ -794,13 +797,13 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
consumerParticipant, err := GetParticipant(ctx, tenant, consumer.AppId, consumer.ServiceName)
if err != nil {
PactLogger.Errorf(nil, "pact publish failed, consumer participant cannot be searched.", in.ConsumerId)
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "consumer participant cannot be searched."),
}, err
}
if consumerParticipant == nil {
id, err := GetData(ctx, GetBrokerLatestParticipantIDKey())
- consumerParticipant = &Participant{Id: int32(id) + 1, AppId: consumer.AppId, ServiceName: consumer.ServiceName}
+ consumerParticipant = &brokerpb.Participant{Id: int32(id) + 1, AppId: consumer.AppId, ServiceName: consumer.ServiceName}
response, err := CreateParticipant(PactLogger, ctx, consumerParticipantKey, *consumerParticipant)
if err != nil {
return response, err
@@ -812,7 +815,7 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
version, err := GetVersion(ctx, tenant, in.Version, consumerParticipant.Id)
if err != nil {
PactLogger.Errorf(nil, "pact publish failed, version cannot be searched.")
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "version cannot be searched."),
}, err
}
@@ -821,7 +824,7 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
PactLogger.Infof("Old version order: %d", order)
order++
id, err := GetData(ctx, GetBrokerLatestVersionIDKey())
- version = &Version{Id: int32(id) + 1, Number: in.Version, ParticipantId: consumerParticipant.Id, Order: order}
+ version = &brokerpb.Version{Id: int32(id) + 1, Number: in.Version, ParticipantId: consumerParticipant.Id, Order: order}
response, err := CreateVersion(PactLogger, ctx, versionKey, *version)
if err != nil {
return response, err
@@ -835,13 +838,13 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
pact, err := GetPact(ctx, tenant, consumerParticipant.Id, providerParticipant.Id, sha)
if err != nil {
PactLogger.Errorf(nil, "pact publish failed, pact cannot be searched.")
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact cannot be searched."),
}, err
}
if pact == nil {
id, err := GetData(ctx, GetBrokerLatestPactIDKey())
- pact = &Pact{Id: int32(id) + 1, ConsumerParticipantId: consumerParticipant.Id,
+ pact = &brokerpb.Pact{Id: int32(id) + 1, ConsumerParticipantId: consumerParticipant.Id,
ProviderParticipantId: providerParticipant.Id, Sha: sha, Content: in.Pact}
response, err := CreatePact(PactLogger, ctx, pactKey, *pact)
if err != nil {
@@ -854,13 +857,13 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
pactVersion, err := GetPactVersion(ctx, tenant, version.Id, pact.Id)
if err != nil {
PactLogger.Errorf(nil, "pact publish failed, pact version cannot be searched.")
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInvalidParams, "pact version cannot be searched."),
}, err
}
if pactVersion == nil {
id, err := GetData(ctx, GetBrokerLatestPactVersionIDKey())
- pactVersion = &PactVersion{Id: int32(id) + 1, VersionId: version.Id, PactId: pact.Id, ProviderParticipantId: providerParticipant.Id}
+ pactVersion = &brokerpb.PactVersion{Id: int32(id) + 1, VersionId: version.Id, PactId: pact.Id, ProviderParticipantId: providerParticipant.Id}
response, err := CreatePactVersion(PactLogger, ctx, pactVersionKey, *pactVersion)
if err != nil {
return response, err
@@ -868,7 +871,7 @@ func (*BrokerService) PublishPact(ctx context.Context, in *PublishPactRequest) (
}
PactLogger.Infof("PactVersion found/create: (%d, %d, %d, %d)", pactVersion.Id, pactVersion.VersionId, pactVersion.PactId, pactVersion.ProviderParticipantId)
PactLogger.Infof("Pact published successfully ...")
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(pb.Response_SUCCESS, "Pact published successfully."),
}, nil
}
diff --git a/server/broker/service_test.go b/server/broker/service_test.go
index ee27320..001bfa5 100644
--- a/server/broker/service_test.go
+++ b/server/broker/service_test.go
@@ -20,6 +20,8 @@ import (
"fmt"
"github.com/apache/incubator-servicecomb-service-center/pkg/util"
+ "github.com/apache/incubator-servicecomb-service-center/server/broker/brokerpb"
+ "github.com/apache/incubator-servicecomb-service-center/server/core"
pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
serviceUtil "github.com/apache/incubator-servicecomb-service-center/server/service/util"
. "github.com/onsi/ginkgo"
@@ -28,9 +30,8 @@ import (
)
const (
- TEST_BROKER_NO_SERVICE_ID = "noServiceId"
- TEST_BROKER_NO_VERSION = "noVersion"
- TEST_BROKER_TOO_LONG_SERVICEID = "addasdfasaddasdfasaddasdfasaddasdfasaddasdfasaddasdfasaddasdfasadafd"
+ TEST_BROKER_NO_SERVICE_ID = "noServiceId"
+ TEST_BROKER_NO_VERSION = "noVersion"
//Consumer
TEST_BROKER_CONSUMER_VERSION = "4.0.0"
TEST_BROKER_CONSUMER_NAME = "broker_name_consumer"
@@ -51,7 +52,7 @@ var _ = Describe("BrokerController", func() {
fmt.Println("UT===========PublishPact")
//(1) create consumer service
- resp, err := serviceResource.Create(getContext(), &pb.CreateServiceRequest{
+ resp, err := core.ServiceAPI.Create(getContext(), &pb.CreateServiceRequest{
Service: &pb.MicroService{
ServiceName: TEST_BROKER_CONSUMER_NAME,
AppId: TEST_BROKER_CONSUMER_APP,
@@ -69,7 +70,7 @@ var _ = Describe("BrokerController", func() {
Expect(resp.GetResponse().Code).To(Equal(pb.Response_SUCCESS))
//(2) create provider service
- resp, err = serviceResource.Create(getContext(), &pb.CreateServiceRequest{
+ resp, err = core.ServiceAPI.Create(getContext(), &pb.CreateServiceRequest{
Service: &pb.MicroService{
ServiceName: TEST_BROKER_PROVIDER_NAME,
AppId: TEST_BROKER_PROVIDER_APP,
@@ -88,7 +89,7 @@ var _ = Describe("BrokerController", func() {
//(3) publish a pact between two services
respPublishPact, err := brokerResource.PublishPact(getContext(),
- &PublishPactRequest{
+ &brokerpb.PublishPactRequest{
ProviderId: providerServiceId,
ConsumerId: consumerServiceId,
Version: TEST_BROKER_CONSUMER_VERSION,
@@ -103,7 +104,7 @@ var _ = Describe("BrokerController", func() {
fmt.Println("UT===========PublishPact, no provider serviceID")
//publish a pact between two services
- respPublishPact, _ := brokerResource.PublishPact(getContext(), &PublishPactRequest{
+ respPublishPact, _ := brokerResource.PublishPact(getContext(), &brokerpb.PublishPactRequest{
ProviderId: TEST_BROKER_NO_SERVICE_ID,
ConsumerId: consumerServiceId,
Version: TEST_BROKER_CONSUMER_VERSION,
@@ -117,7 +118,7 @@ var _ = Describe("BrokerController", func() {
fmt.Println("UT===========PublishPact, no consumer serviceID")
//publish a pact between two services
- respPublishPact, _ := brokerResource.PublishPact(getContext(), &PublishPactRequest{
+ respPublishPact, _ := brokerResource.PublishPact(getContext(), &brokerpb.PublishPactRequest{
ProviderId: providerServiceId,
ConsumerId: TEST_BROKER_NO_SERVICE_ID,
Version: TEST_BROKER_CONSUMER_VERSION,
@@ -131,7 +132,7 @@ var _ = Describe("BrokerController", func() {
fmt.Println("UT===========PublishPact, no consumer Version")
//publish a pact between two services
- respPublishPact, _ := brokerResource.PublishPact(getContext(), &PublishPactRequest{
+ respPublishPact, _ := brokerResource.PublishPact(getContext(), &brokerpb.PublishPactRequest{
ProviderId: providerServiceId,
ConsumerId: consumerServiceId,
Version: TEST_BROKER_NO_VERSION,
@@ -144,7 +145,7 @@ var _ = Describe("BrokerController", func() {
It("GetBrokerHome", func() {
fmt.Println("UT===========GetBrokerHome")
- respGetHome, _ := brokerResource.GetBrokerHome(getContext(), &BaseBrokerRequest{
+ respGetHome, _ := brokerResource.GetBrokerHome(getContext(), &brokerpb.BaseBrokerRequest{
HostAddress: "localhost",
Scheme: "http",
})
@@ -157,9 +158,9 @@ var _ = Describe("BrokerController", func() {
fmt.Println("UT===========GetBrokerAllProviderPacts")
respGetAllProviderPacts, _ := brokerResource.GetAllProviderPacts(getContext(),
- &GetAllProviderPactsRequest{
+ &brokerpb.GetAllProviderPactsRequest{
ProviderId: providerServiceId,
- BaseUrl: &BaseBrokerRequest{
+ BaseUrl: &brokerpb.BaseBrokerRequest{
HostAddress: "localhost",
Scheme: "http",
}})
@@ -172,11 +173,11 @@ var _ = Describe("BrokerController", func() {
fmt.Println("UT===========GetBrokerPactsOfProvider")
respGetAllProviderPacts, _ := brokerResource.GetPactsOfProvider(getContext(),
- &GetProviderConsumerVersionPactRequest{
+ &brokerpb.GetProviderConsumerVersionPactRequest{
ProviderId: providerServiceId,
ConsumerId: consumerServiceId,
Version: TEST_BROKER_CONSUMER_VERSION,
- BaseUrl: &BaseBrokerRequest{
+ BaseUrl: &brokerpb.BaseBrokerRequest{
HostAddress: "localhost",
Scheme: "http",
}})
@@ -185,6 +186,51 @@ var _ = Describe("BrokerController", func() {
Expect(respGetAllProviderPacts.GetResponse().Code).To(Equal(pb.Response_SUCCESS))
})
+ It("PublishVerificationResults", func() {
+ fmt.Println("UT===========PublishVerificationResults")
+
+ id, err := GetData(context.Background(), GetBrokerLatestPactIDKey())
+ Expect(err).To(BeNil())
+ respResults, err := brokerResource.PublishVerificationResults(getContext(),
+ &brokerpb.PublishVerificationRequest{
+ ProviderId: providerServiceId,
+ ConsumerId: consumerServiceId,
+ PactId: int32(id),
+ ProviderApplicationVersion: TEST_BROKER_PROVIDER_VERSION,
+ })
+
+ Expect(respResults).NotTo(BeNil())
+ Expect(respResults.GetResponse().Code).To(Equal(pb.Response_SUCCESS))
+ })
+
+ It("RetrieveVerificationResults", func() {
+ fmt.Println("UT===========RetrieveVerificationResults")
+
+ respVerification, _ := brokerResource.RetrieveVerificationResults(getContext(),
+ &brokerpb.RetrieveVerificationRequest{
+ ConsumerId: consumerServiceId,
+ ConsumerVersion: TEST_BROKER_CONSUMER_VERSION,
+ })
+
+ Expect(respVerification).NotTo(BeNil())
+ Expect(respVerification.GetResponse().Code).To(Equal(pb.Response_SUCCESS))
+ })
+
+ It("RetrieveProviderPacts", func() {
+ fmt.Println("UT===========RetrieveProviderPacts")
+
+ respProviderPact, _ := brokerResource.RetrieveProviderPacts(getContext(),
+ &brokerpb.GetAllProviderPactsRequest{
+ ProviderId: providerServiceId,
+ BaseUrl: &brokerpb.BaseBrokerRequest{
+ HostAddress: "localhost",
+ Scheme: "http",
+ },
+ })
+
+ Expect(respProviderPact).NotTo(BeNil())
+ Expect(respProviderPact.GetResponse().Code).To(Equal(pb.Response_SUCCESS))
+ })
})
})
})
diff --git a/server/broker/store.go b/server/broker/store.go
index cb73923..0754c0c 100644
--- a/server/broker/store.go
+++ b/server/broker/store.go
@@ -33,13 +33,13 @@ var (
var brokerKvStore = &BKvStore{}
func init() {
- PARTICIPANT = backend.Store().MustInstall(backend.NewEntity("PARTICIPANT", backend.DefaultConfig().WithPrefix(GetBrokerParticipantKey(""))))
- VERSION = backend.Store().MustInstall(backend.NewEntity("VERSION", backend.DefaultConfig().WithPrefix(GetBrokerVersionKey(""))))
- PACT = backend.Store().MustInstall(backend.NewEntity("PACT", backend.DefaultConfig().WithPrefix(GetBrokerPactKey(""))))
- PACT_VERSION = backend.Store().MustInstall(backend.NewEntity("PACT_VERSION", backend.DefaultConfig().WithPrefix(GetBrokerPactVersionKey(""))))
- PACT_TAG = backend.Store().MustInstall(backend.NewEntity("PACT_TAG", backend.DefaultConfig().WithPrefix(GetBrokerTagKey(""))))
- VERIFICATION = backend.Store().MustInstall(backend.NewEntity("VERIFICATION", backend.DefaultConfig().WithPrefix(GetBrokerVerificationKey(""))))
- PACT_LATEST = backend.Store().MustInstall(backend.NewEntity("PACT_LATEST", backend.DefaultConfig().WithPrefix(GetBrokerLatestKey(""))))
+ PARTICIPANT = backend.Store().MustInstall(backend.NewExtension("PARTICIPANT", backend.Configure().WithPrefix(GetBrokerParticipantKey(""))))
+ VERSION = backend.Store().MustInstall(backend.NewExtension("VERSION", backend.Configure().WithPrefix(GetBrokerVersionKey(""))))
+ PACT = backend.Store().MustInstall(backend.NewExtension("PACT", backend.Configure().WithPrefix(GetBrokerPactKey(""))))
+ PACT_VERSION = backend.Store().MustInstall(backend.NewExtension("PACT_VERSION", backend.Configure().WithPrefix(GetBrokerPactVersionKey(""))))
+ PACT_TAG = backend.Store().MustInstall(backend.NewExtension("PACT_TAG", backend.Configure().WithPrefix(GetBrokerTagKey(""))))
+ VERIFICATION = backend.Store().MustInstall(backend.NewExtension("VERIFICATION", backend.Configure().WithPrefix(GetBrokerVerificationKey(""))))
+ PACT_LATEST = backend.Store().MustInstall(backend.NewExtension("PACT_LATEST", backend.Configure().WithPrefix(GetBrokerLatestKey(""))))
}
@@ -47,31 +47,31 @@ type BKvStore struct {
}
func (s *BKvStore) Participant() backend.Indexer {
- return backend.Store().Entity(PARTICIPANT)
+ return backend.Store().Entities(PARTICIPANT)
}
func (s *BKvStore) Version() backend.Indexer {
- return backend.Store().Entity(VERSION)
+ return backend.Store().Entities(VERSION)
}
func (s *BKvStore) Pact() backend.Indexer {
- return backend.Store().Entity(PACT)
+ return backend.Store().Entities(PACT)
}
func (s *BKvStore) PactVersion() backend.Indexer {
- return backend.Store().Entity(PACT_VERSION)
+ return backend.Store().Entities(PACT_VERSION)
}
func (s *BKvStore) PactTag() backend.Indexer {
- return backend.Store().Entity(PACT_TAG)
+ return backend.Store().Entities(PACT_TAG)
}
func (s *BKvStore) Verification() backend.Indexer {
- return backend.Store().Entity(VERIFICATION)
+ return backend.Store().Entities(VERIFICATION)
}
func (s *BKvStore) PactLatest() backend.Indexer {
- return backend.Store().Entity(PACT_LATEST)
+ return backend.Store().Entities(PACT_LATEST)
}
func Store() *BKvStore {
diff --git a/server/broker/util.go b/server/broker/util.go
index 3d398b5..8f8e70a 100644
--- a/server/broker/util.go
+++ b/server/broker/util.go
@@ -19,7 +19,6 @@ package broker
import (
"context"
"encoding/json"
- "errors"
"math"
"net/url"
"strconv"
@@ -27,6 +26,7 @@ import (
"github.com/ServiceComb/paas-lager/third_party/forked/cloudfoundry/lager"
"github.com/apache/incubator-servicecomb-service-center/pkg/util"
+ "github.com/apache/incubator-servicecomb-service-center/server/broker/brokerpb"
"github.com/apache/incubator-servicecomb-service-center/server/core"
"github.com/apache/incubator-servicecomb-service-center/server/core/backend"
pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
@@ -132,27 +132,27 @@ func GetBrokerHomeLinksAPIS(scheme string, host string, apiKey string) string {
}
//CreateBrokerHomeResponse create the templated broker home response
-func CreateBrokerHomeResponse(host string, scheme string) *BrokerHomeResponse {
+func CreateBrokerHomeResponse(host string, scheme string) *brokerpb.BrokerHomeResponse {
- var apiEntries map[string]*BrokerAPIInfoEntry
- apiEntries = make(map[string]*BrokerAPIInfoEntry)
+ var apiEntries map[string]*brokerpb.BrokerAPIInfoEntry
+ apiEntries = make(map[string]*brokerpb.BrokerAPIInfoEntry)
for k := range brokerAPILinksValues {
- apiEntries[k] = &BrokerAPIInfoEntry{
+ apiEntries[k] = &brokerpb.BrokerAPIInfoEntry{
Href: GetBrokerHomeLinksAPIS(scheme, host, k),
Title: brokerAPILinksTitles[k],
Templated: brokerAPILinksTempl[k],
}
}
- curies := []*BrokerAPIInfoEntry{}
- curies = append(curies, &BrokerAPIInfoEntry{
+ curies := []*brokerpb.BrokerAPIInfoEntry{}
+ curies = append(curies, &brokerpb.BrokerAPIInfoEntry{
Name: "pb",
Href: GenerateBrokerAPIPath(scheme, host, BROKER_CURIES_URL,
strings.NewReplacer(":rel", "{rel}")),
})
- return &BrokerHomeResponse{
+ return &brokerpb.BrokerHomeResponse{
Response: pb.CreateResponse(pb.Response_SUCCESS, "Broker Home."),
XLinks: apiEntries,
Curies: curies,
@@ -160,7 +160,7 @@ func CreateBrokerHomeResponse(host string, scheme string) *BrokerHomeResponse {
}
//GetBrokerHomeResponse gets the homeResponse from cache if it exists
-func GetBrokerHomeResponse(host string, scheme string) *BrokerHomeResponse {
+func GetBrokerHomeResponse(host string, scheme string) *brokerpb.BrokerHomeResponse {
brokerResp := CreateBrokerHomeResponse(host, scheme)
if brokerResp == nil {
return nil
@@ -168,87 +168,8 @@ func GetBrokerHomeResponse(host string, scheme string) *BrokerHomeResponse {
return brokerResp
}
-//GetBrokerParticipantUtils returns the participant from ETCD
-func GetBrokerParticipantUtils(ctx context.Context, tenant string, appId string,
- serviceName string, opts ...registry.PluginOpOption) (*Participant, error) {
-
- key := GenerateBrokerParticipantKey(tenant, appId, serviceName)
- opts = append(opts, registry.WithStrKey(key))
- participants, err := Store().Participant().Search(ctx, opts...)
-
- if err != nil {
- PactLogger.Errorf(nil, "pact publish failed, participant with, could not be searched.")
- return nil, err
- }
-
- if len(participants.Kvs) == 0 {
- PactLogger.Info("GetParticipant found no participant")
- return nil, nil
- }
-
- participant := &Participant{}
- err = json.Unmarshal(participants.Kvs[0].Value.([]byte), participant)
- if err != nil {
- return nil, err
- }
- PactLogger.Infof("GetParticipant: (%d, %s, %s)", participant.Id, participant.AppId,
- participant.ServiceName)
- return participant, nil
-}
-
-//GetBrokerParticipantFromServiceId returns the participant and the service from ETCD
-func GetBrokerParticipantFromServiceId(ctx context.Context, serviceId string) (*Participant,
- *pb.MicroService, error, error) {
-
- tenant := GetDefaultTenantProject()
- serviceParticipant, err := serviceUtil.GetService(ctx, tenant, serviceId)
- if err != nil {
- PactLogger.Errorf(err,
- "get participant failed, serviceId is %s: query provider failed.", serviceId)
- return nil, nil, nil, err
- }
- if serviceParticipant == nil {
- PactLogger.Errorf(nil,
- "get participant failed, serviceId is %s: service not exist.", serviceId)
- return nil, nil, nil, errors.New("get participant, serviceId not exist.")
- }
- // Get or create provider participant
- participant, errBroker := GetBrokerParticipantUtils(ctx, tenant, serviceParticipant.AppId,
- serviceParticipant.ServiceName)
- if errBroker != nil {
- PactLogger.Errorf(errBroker,
- "get participant failed, serviceId %s: query participant failed.", serviceId)
- return nil, serviceParticipant, errBroker, err
- }
- if participant == nil {
- PactLogger.Errorf(nil,
- "get participant failed, particpant does not exist for serviceId %s", serviceId)
- return nil, serviceParticipant, errors.New("particpant does not exist for serviceId."), err
- }
-
- return participant, serviceParticipant, errBroker, nil
-}
-
-//GetBrokerParticipantFromService returns the participant given the microservice
-func GetBrokerParticipantFromService(ctx context.Context,
- microservice *pb.MicroService) (*Participant, error) {
- if microservice == nil {
- return nil, nil
- }
- tenant := GetDefaultTenantProject()
- participant, errBroker := GetBrokerParticipantUtils(ctx, tenant, microservice.AppId,
- microservice.ServiceName)
- if errBroker != nil {
- PactLogger.Errorf(errBroker,
- "get participant failed, serviceId %s: query participant failed.",
- microservice.ServiceId)
- return nil, errBroker
- }
- return participant, errBroker
-}
-
func GetParticipant(ctx context.Context, domain string, appId string,
- serviceName string) (*Participant, error) {
+ serviceName string) (*brokerpb.Participant, error) {
key := GenerateBrokerParticipantKey(domain, appId, serviceName)
participants, err := Store().Participant().Search(ctx, registry.WithStrKey(key))
if err != nil {
@@ -258,7 +179,7 @@ func GetParticipant(ctx context.Context, domain string, appId string,
PactLogger.Info("GetParticipant found no participant")
return nil, nil
}
- participant := &Participant{}
+ participant := &brokerpb.Participant{}
err = json.Unmarshal(participants.Kvs[0].Value.([]byte), participant)
if err != nil {
return nil, err
@@ -268,7 +189,7 @@ func GetParticipant(ctx context.Context, domain string, appId string,
}
func GetVersion(ctx context.Context, domain string, number string,
- participantId int32) (*Version, error) {
+ participantId int32) (*brokerpb.Version, error) {
key := GenerateBrokerVersionKey(domain, number, participantId)
versions, err := Store().Version().Search(ctx, registry.WithStrKey(key))
if err != nil {
@@ -277,7 +198,7 @@ func GetVersion(ctx context.Context, domain string, number string,
if len(versions.Kvs) == 0 {
return nil, nil
}
- version := &Version{}
+ version := &brokerpb.Version{}
err = json.Unmarshal(versions.Kvs[0].Value.([]byte), version)
if err != nil {
return nil, err
@@ -286,7 +207,7 @@ func GetVersion(ctx context.Context, domain string, number string,
return version, nil
}
-func GetPact(ctx context.Context, domain string, consumerParticipantId int32, producerParticipantId int32, sha []byte) (*Pact, error) {
+func GetPact(ctx context.Context, domain string, consumerParticipantId int32, producerParticipantId int32, sha []byte) (*brokerpb.Pact, error) {
key := GenerateBrokerPactKey(domain, consumerParticipantId, producerParticipantId, sha)
versions, err := Store().Pact().Search(ctx, registry.WithStrKey(key))
if err != nil {
@@ -295,7 +216,7 @@ func GetPact(ctx context.Context, domain string, consumerParticipantId int32, pr
if len(versions.Kvs) == 0 {
return nil, nil
}
- pact := &Pact{}
+ pact := &brokerpb.Pact{}
err = json.Unmarshal(versions.Kvs[0].Value.([]byte), pact)
if err != nil {
return nil, err
@@ -305,7 +226,7 @@ func GetPact(ctx context.Context, domain string, consumerParticipantId int32, pr
}
func GetPactVersion(ctx context.Context, domain string, versionId int32,
- pactId int32) (*PactVersion, error) {
+ pactId int32) (*brokerpb.PactVersion, error) {
key := GenerateBrokerPactVersionKey(domain, versionId, pactId)
versions, err := Store().PactVersion().Search(ctx, registry.WithStrKey(key))
if err != nil {
@@ -314,7 +235,7 @@ func GetPactVersion(ctx context.Context, domain string, versionId int32,
if len(versions.Kvs) == 0 {
return nil, nil
}
- pactVersion := &PactVersion{}
+ pactVersion := &brokerpb.PactVersion{}
err = json.Unmarshal(versions.Kvs[0].Value.([]byte), pactVersion)
if err != nil {
return nil, err
@@ -345,11 +266,11 @@ func StoreData(ctx context.Context, key string, value string) error {
return err
}
-func CreateParticipant(pactLogger lager.Logger, ctx context.Context, participantKey string, participant Participant) (*PublishPactResponse, error) {
+func CreateParticipant(pactLogger lager.Logger, ctx context.Context, participantKey string, participant brokerpb.Participant) (*brokerpb.PublishPactResponse, error) {
data, err := json.Marshal(participant)
if err != nil {
PactLogger.Errorf(nil, "pact publish failed, participant cannot be created.")
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "participant cannot be created."),
}, err
}
@@ -360,7 +281,7 @@ func CreateParticipant(pactLogger lager.Logger, ctx context.Context, participant
if err != nil {
PactLogger.Errorf(nil, "pact publish failed, participant cannot be created.")
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "participant cannot be created."),
}, err
}
@@ -371,7 +292,7 @@ func CreateParticipant(pactLogger lager.Logger, ctx context.Context, participant
err = StoreData(ctx, k, v)
if err != nil {
PactLogger.Errorf(nil, "pact publish failed, participant cannot be created.")
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "participant cannot be created."),
}, err
}
@@ -380,11 +301,11 @@ func CreateParticipant(pactLogger lager.Logger, ctx context.Context, participant
}
func CreateVersion(pactLogger lager.Logger, ctx context.Context, versionKey string,
- version Version) (*PublishPactResponse, error) {
+ version brokerpb.Version) (*brokerpb.PublishPactResponse, error) {
data, err := json.Marshal(version)
if err != nil {
PactLogger.Errorf(nil, "pact publish failed, version cannot be created.")
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "version cannot be created."),
}, err
}
@@ -394,7 +315,7 @@ func CreateVersion(pactLogger lager.Logger, ctx context.Context, versionKey stri
registry.WithValue(data))
if err != nil {
PactLogger.Errorf(nil, "pact publish failed, version cannot be created.")
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "version cannot be created."),
}, err
}
@@ -404,7 +325,7 @@ func CreateVersion(pactLogger lager.Logger, ctx context.Context, versionKey stri
err = StoreData(ctx, k, v)
if err != nil {
PactLogger.Errorf(nil, "pact publish failed, version cannot be created.")
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "version cannot be created."),
}, err
}
@@ -413,11 +334,11 @@ func CreateVersion(pactLogger lager.Logger, ctx context.Context, versionKey stri
}
func CreatePact(pactLogger lager.Logger, ctx context.Context,
- pactKey string, pact Pact) (*PublishPactResponse, error) {
+ pactKey string, pact brokerpb.Pact) (*brokerpb.PublishPactResponse, error) {
data, err := json.Marshal(pact)
if err != nil {
PactLogger.Errorf(nil, "pact publish failed, pact cannot be created.")
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "pact cannot be created."),
}, err
}
@@ -429,7 +350,7 @@ func CreatePact(pactLogger lager.Logger, ctx context.Context,
if err != nil {
PactLogger.Errorf(nil, "pact publish failed, pact cannot be created.")
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "pact cannot be created."),
}, err
}
@@ -439,7 +360,7 @@ func CreatePact(pactLogger lager.Logger, ctx context.Context,
err = StoreData(ctx, k, v)
if err != nil {
PactLogger.Errorf(nil, "pact publish failed, pact cannot be created.")
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "pact cannot be created."),
}, err
}
@@ -447,11 +368,11 @@ func CreatePact(pactLogger lager.Logger, ctx context.Context,
return nil, nil
}
-func CreatePactVersion(pactLogger lager.Logger, ctx context.Context, pactVersionKey string, pactVersion PactVersion) (*PublishPactResponse, error) {
+func CreatePactVersion(pactLogger lager.Logger, ctx context.Context, pactVersionKey string, pactVersion brokerpb.PactVersion) (*brokerpb.PublishPactResponse, error) {
data, err := json.Marshal(pactVersion)
if err != nil {
PactLogger.Errorf(nil, "pact publish failed, pact version cannot be created.")
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "pact version cannot be created."),
}, err
}
@@ -460,7 +381,7 @@ func CreatePactVersion(pactLogger lager.Logger, ctx context.Context, pactVersion
registry.PUT, registry.WithValue(data), registry.WithStrKey(pactVersionKey))
if err != nil {
PactLogger.Errorf(nil, "pact publish failed, pact version cannot be created.")
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "pact version cannot be created."),
}, err
}
@@ -470,7 +391,7 @@ func CreatePactVersion(pactLogger lager.Logger, ctx context.Context, pactVersion
err = StoreData(ctx, k, v)
if err != nil {
PactLogger.Errorf(nil, "pact publish failed, pact version cannot be created.")
- return &PublishPactResponse{
+ return &brokerpb.PublishPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "pact version cannot be created."),
}, err
}
@@ -479,11 +400,11 @@ func CreatePactVersion(pactLogger lager.Logger, ctx context.Context, pactVersion
}
func CreateVerification(pactLogger lager.Logger, ctx context.Context,
- verificationKey string, verification Verification) (*PublishVerificationResponse, error) {
+ verificationKey string, verification brokerpb.Verification) (*brokerpb.PublishVerificationResponse, error) {
data, err := json.Marshal(verification)
if err != nil {
PactLogger.Errorf(nil, "verification result publish failed, verification result marshal error.")
- return &PublishVerificationResponse{
+ return &brokerpb.PublishVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "verification result marshal error."),
}, err
}
@@ -493,7 +414,7 @@ func CreateVerification(pactLogger lager.Logger, ctx context.Context,
registry.WithValue(data))
if err != nil {
PactLogger.Errorf(nil, "verification result publish failed, verification result cannot be created.")
- return &PublishVerificationResponse{
+ return &brokerpb.PublishVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "verification result cannot be created."),
}, err
}
@@ -503,7 +424,7 @@ func CreateVerification(pactLogger lager.Logger, ctx context.Context,
err = StoreData(ctx, k, v)
if err != nil {
PactLogger.Errorf(nil, "verification result publish failed, verification result cannot be created.")
- return &PublishVerificationResponse{
+ return &brokerpb.PublishVerificationResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "verification result cannot be created."),
}, err
}
@@ -524,7 +445,7 @@ func GetLastestVersionNumberForParticipant(ctx context.Context,
}
order := int32(math.MinInt32)
for i := 0; i < len(versions.Kvs); i++ {
- version := &Version{}
+ version := &brokerpb.Version{}
err = json.Unmarshal(versions.Kvs[i].Value.([]byte), &version)
if err != nil {
return -1
@@ -540,10 +461,10 @@ func GetLastestVersionNumberForParticipant(ctx context.Context,
}
func RetrieveProviderConsumerPact(ctx context.Context,
- in *GetProviderConsumerVersionPactRequest) (*GetProviderConsumerVersionPactResponse, int32, error) {
+ in *brokerpb.GetProviderConsumerVersionPactRequest) (*brokerpb.GetProviderConsumerVersionPactResponse, int32, error) {
if in == nil || len(in.ProviderId) == 0 || len(in.ConsumerId) == 0 || len(in.Version) == 0 {
PactLogger.Errorf(nil, "pact retrieve request failed: invalid params.")
- return &GetProviderConsumerVersionPactResponse{
+ return &brokerpb.GetProviderConsumerVersionPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "Request format invalid."),
}, -1, nil
}
@@ -552,13 +473,13 @@ func RetrieveProviderConsumerPact(ctx context.Context,
provider, err := serviceUtil.GetService(ctx, tenant, in.ProviderId)
if err != nil {
PactLogger.Errorf(err, "pact retrieve failed, providerId is %s: query provider failed.", in.ProviderId)
- return &GetProviderConsumerVersionPactResponse{
+ return &brokerpb.GetProviderConsumerVersionPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "Query provider failed."),
}, -1, err
}
if provider == nil {
PactLogger.Errorf(nil, "pact retrieve failed, providerId is %s: provider not exist.", in.ProviderId)
- return &GetProviderConsumerVersionPactResponse{
+ return &brokerpb.GetProviderConsumerVersionPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "Provider does not exist."),
}, -1, nil
}
@@ -566,13 +487,13 @@ func RetrieveProviderConsumerPact(ctx context.Context,
consumer, err := serviceUtil.GetService(ctx, tenant, in.ConsumerId)
if err != nil {
PactLogger.Errorf(err, "pact retrieve failed, consumerId is %s: query consumer failed.", in.ConsumerId)
- return &GetProviderConsumerVersionPactResponse{
+ return &brokerpb.GetProviderConsumerVersionPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "Query consumer failed."),
}, -1, err
}
if consumer == nil {
PactLogger.Errorf(nil, "pact retrieve failed, consumerId is %s: consumer not exist.", in.ConsumerId)
- return &GetProviderConsumerVersionPactResponse{
+ return &brokerpb.GetProviderConsumerVersionPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "Consumer does not exist."),
}, -1, nil
}
@@ -581,7 +502,7 @@ func RetrieveProviderConsumerPact(ctx context.Context,
providerParticipant, err := GetParticipant(ctx, tenant, provider.AppId, provider.ServiceName)
if err != nil || providerParticipant == nil {
PactLogger.Errorf(nil, "pact retrieve failed, provider participant %s cannot be searched.", in.ProviderId)
- return &GetProviderConsumerVersionPactResponse{
+ return &brokerpb.GetProviderConsumerVersionPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "Provider participant cannot be searched."),
}, -1, err
}
@@ -590,7 +511,7 @@ func RetrieveProviderConsumerPact(ctx context.Context,
consumerParticipant, err := GetParticipant(ctx, tenant, consumer.AppId, consumer.ServiceName)
if err != nil || consumerParticipant == nil {
PactLogger.Errorf(nil, "pact retrieve failed, consumer participant %s cannot be searched.", in.ConsumerId)
- return &GetProviderConsumerVersionPactResponse{
+ return &brokerpb.GetProviderConsumerVersionPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "consumer participant cannot be searched."),
}, -1, err
}
@@ -599,7 +520,7 @@ func RetrieveProviderConsumerPact(ctx context.Context,
version, err := GetVersion(ctx, tenant, in.Version, consumerParticipant.Id)
if err != nil || version == nil {
PactLogger.Errorf(nil, "pact retrieve failed, version cannot be searched.")
- return &GetProviderConsumerVersionPactResponse{
+ return &brokerpb.GetProviderConsumerVersionPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "version cannot be searched."),
}, -1, err
}
@@ -621,7 +542,7 @@ func RetrieveProviderConsumerPact(ctx context.Context,
}
pactIds := make(map[int32]int32)
for i := 0; i < len(pactVersions.Kvs); i++ {
- pactVersion := &PactVersion{}
+ pactVersion := &brokerpb.PactVersion{}
err = json.Unmarshal(pactVersions.Kvs[i].Value.([]byte), pactVersion)
if err != nil {
return nil, -1, err
@@ -634,7 +555,7 @@ func RetrieveProviderConsumerPact(ctx context.Context,
}
if len(pactIds) == 0 {
PactLogger.Errorf(nil, "pact retrieve failed, pact cannot be found.")
- return &GetProviderConsumerVersionPactResponse{
+ return &brokerpb.GetProviderConsumerVersionPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "pact cannot be found."),
}, -1, err
}
@@ -643,7 +564,7 @@ func RetrieveProviderConsumerPact(ctx context.Context,
strconv.Itoa(int(consumerParticipant.Id)),
strconv.Itoa(int(providerParticipant.Id))},
"/")
- pacts, err := Store().PactVersion().Search(ctx,
+ pacts, err := Store().Pact().Search(ctx,
registry.WithStrKey(pactKey),
registry.WithPrefix())
@@ -655,27 +576,27 @@ func RetrieveProviderConsumerPact(ctx context.Context,
return nil, -1, nil
}
for i := 0; i < len(pacts.Kvs); i++ {
- pactObj := &Pact{}
+ pactObj := &brokerpb.Pact{}
err = json.Unmarshal(pacts.Kvs[i].Value.([]byte), pactObj)
if err != nil {
return nil, -1, err
}
if _, ok := pactIds[pactObj.Id]; ok {
//PactLogger.Infof("pact retrieve succeeded, found pact: %s", string(pactObj.Content))
- return &GetProviderConsumerVersionPactResponse{
+ return &brokerpb.GetProviderConsumerVersionPactResponse{
Response: pb.CreateResponse(pb.Response_SUCCESS, "pact found."),
Pact: pactObj.Content,
}, pactObj.Id, nil
}
}
PactLogger.Errorf(nil, "pact retrieve failed, pact cannot be found.")
- return &GetProviderConsumerVersionPactResponse{
+ return &brokerpb.GetProviderConsumerVersionPactResponse{
Response: pb.CreateResponse(scerr.ErrInternal, "pact cannot be found."),
}, -1, nil
}
func DeletePactData(ctx context.Context,
- in *BaseBrokerRequest) (*pb.Response, error) {
+ in *brokerpb.BaseBrokerRequest) (*pb.Response, error) {
//tenant := util.ParseTenantProject(ctx)
allPactKey := GetBrokerRootKey() //GetBrokerVerificationKey("default") //util.StringJoin([]string{ apt.GetRootKey(), apt.REGISTRY_PACT_ROOT_KEY }, "/")
diff --git a/server/core/backend/cache.go b/server/core/backend/cache.go
index 2f9107e..acf9b99 100644
--- a/server/core/backend/cache.go
+++ b/server/core/backend/cache.go
@@ -18,10 +18,11 @@ package backend
type Cache interface {
Name() string
- Size() int
+ Size() int // the bytes size of the cache
Get(k string) *KeyValue
- GetAll(prefix string, arr *[]*KeyValue) int
+ GetAll(arr *[]*KeyValue) int
+ GetPrefix(prefix string, arr *[]*KeyValue) int
ForEach(iter func(k string, v *KeyValue) (next bool))
Put(k string, v *KeyValue)
@@ -30,7 +31,4 @@ type Cache interface {
type Cacher interface {
Cache() Cache
- Run()
- Stop()
- Ready() <-chan struct{}
}
diff --git a/server/core/backend/cache_kv.go b/server/core/backend/cache_kv.go
index b001544..8b5d865 100644
--- a/server/core/backend/cache_kv.go
+++ b/server/core/backend/cache_kv.go
@@ -17,6 +17,7 @@
package backend
import (
+ "github.com/apache/incubator-servicecomb-service-center/pkg/util"
"strings"
"sync"
"time"
@@ -36,7 +37,9 @@ func (c *KvCache) Name() string {
}
func (c *KvCache) Size() (l int) {
- l = c.GetAll(c.Cfg.Prefix, nil)
+ c.rwMux.RLock()
+ l = int(util.Sizeof(c.store))
+ c.rwMux.RUnlock()
return
}
@@ -50,7 +53,14 @@ func (c *KvCache) Get(key string) (v *KeyValue) {
return
}
-func (c *KvCache) GetAll(prefix string, arr *[]*KeyValue) (count int) {
+func (c *KvCache) GetAll(arr *[]*KeyValue) (count int) {
+ c.rwMux.RLock()
+ count = c.getPrefixKey(arr, c.Cfg.Key)
+ c.rwMux.RUnlock()
+ return
+}
+
+func (c *KvCache) GetPrefix(prefix string, arr *[]*KeyValue) (count int) {
c.rwMux.RLock()
count = c.getPrefixKey(arr, prefix)
c.rwMux.RUnlock()
@@ -116,7 +126,7 @@ func (c *KvCache) getPrefixKey(arr *[]*KeyValue, prefix string) (count int) {
}
func (c *KvCache) addPrefixKey(key string, val *KeyValue) {
- if len(c.Cfg.Prefix) >= len(key) {
+ if len(c.Cfg.Key) >= len(key) {
return
}
prefix := c.prefix(key)
@@ -155,12 +165,6 @@ func (c *KvCache) deletePrefixKey(key string) {
}
}
-func (c *KvCache) ReportMetrics() {
- c.rwMux.RLock()
- ReportCacheMetrics(c.Name(), "raw", c.store)
- c.rwMux.RUnlock()
-}
-
func NewKvCache(name string, cfg *Config) *KvCache {
return &KvCache{
Cfg: cfg,
diff --git a/server/core/backend/cache_null.go b/server/core/backend/cache_null.go
index cce930e..8d538d6 100644
--- a/server/core/backend/cache_null.go
+++ b/server/core/backend/cache_null.go
@@ -24,22 +24,17 @@ var (
type nullCache struct {
}
-func (n *nullCache) Name() string { return "null" }
+func (n *nullCache) Name() string { return "NULL" }
func (n *nullCache) Size() int { return 0 }
-func (n *nullCache) RLock() {}
-func (n *nullCache) RUnlock() {}
func (n *nullCache) Get(k string) *KeyValue { return nil }
-func (n *nullCache) GetAll(prefix string, arr *[]*KeyValue) int { return 0 }
+func (n *nullCache) GetAll(arr *[]*KeyValue) int { return 0 }
+func (n *nullCache) GetPrefix(prefix string, arr *[]*KeyValue) int { return 0 }
func (n *nullCache) ForEach(iter func(k string, v *KeyValue) (next bool)) {}
-func (n *nullCache) Lock() {}
-func (n *nullCache) Unlock() {}
func (n *nullCache) Put(k string, v *KeyValue) {}
func (n *nullCache) Remove(k string) {}
type nullCacher struct {
}
-func (n *nullCacher) Cache() Cache { return NullCache }
-func (n *nullCacher) Run() {}
-func (n *nullCacher) Stop() {}
-func (n *nullCacher) Ready() <-chan struct{} { return closedCh }
+func (n *nullCacher) Config() *Config { return nil }
+func (n *nullCacher) Cache() Cache { return NullCache }
diff --git a/server/core/backend/cache_test.go b/server/core/backend/cache_test.go
index e15ba9c..b959322 100644
--- a/server/core/backend/cache_test.go
+++ b/server/core/backend/cache_test.go
@@ -35,7 +35,7 @@ func BenchmarkFilter(b *testing.B) {
}
v, _ := json.Marshal(inst)
- cfg := DefaultConfig().WithParser(InstanceParser)
+ cfg := Configure().WithParser(InstanceParser)
n := 300 * 1000 // 30w
cache := NewKvCache("test", cfg)
@@ -83,8 +83,36 @@ func BenchmarkFilter(b *testing.B) {
//20 82367261 ns/op 37964987 B/op 80132 allocs/op
}
+func TestNullCache_Name(t *testing.T) {
+ NullCache.Put("", nil)
+ if NullCache.Name() != "NULL" {
+ t.Fatalf("TestNullCache_Name failed")
+ }
+ if NullCache.Size() != 0 {
+ t.Fatalf("TestNullCache_Name failed")
+ }
+ if NullCache.Get("") != nil {
+ t.Fatalf("TestNullCache_Name failed")
+ }
+ if NullCache.GetAll(nil) != 0 {
+ t.Fatalf("TestNullCache_Name failed")
+ }
+ if NullCache.GetPrefix("", nil) != 0 {
+ t.Fatalf("TestNullCache_Name failed")
+ }
+ NullCache.ForEach(func(k string, v *KeyValue) (next bool) {
+ t.Fatalf("TestNullCache_Name failed")
+ return false
+ })
+ NullCache.Remove("")
+
+ if NullCacher.Cache() != NullCache || NullCacher.Config() != nil {
+ t.Fatalf("TestNullCache_Name failed")
+ }
+}
+
func TestKvCache_Get(t *testing.T) {
- c := NewKvCache("test", DefaultConfig())
+ c := NewKvCache("test", Configure())
c.Put("", &KeyValue{Version: 1})
c.Put("/", &KeyValue{Version: 1})
c.Put("/a/b/c/d/e/1", &KeyValue{Version: 1})
@@ -92,21 +120,25 @@ func TestKvCache_Get(t *testing.T) {
c.Put("/a/b/d/d/f/3", &KeyValue{Version: 3})
c.Put("/a/b/e/d/g/4", &KeyValue{Version: 4})
- if l := c.Size(); l != 4 {
- t.Fatalf("TestKvCache Size() failed, %d", l)
+ if s := c.Size(); s == 0 {
+ t.Fatalf("TestKvCache Size() failed, %d", s)
+ }
+
+ if l := c.GetAll(nil); l != 4 {
+ t.Fatalf("TestKvCache GetAll() failed, %d", l)
}
if kv := c.Get("/a/b/c/d/e/2"); kv == nil || kv.Version != 2 {
t.Fatalf("TestKvCache Get() failed, %v", kv)
}
- if l := c.GetAll("/", nil); l != 4 {
- t.Fatalf("TestKvCache GetAll() failed, %d", l)
+ if l := c.GetPrefix("/", nil); l != 4 {
+ t.Fatalf("TestKvCache GetPrefix() failed, %d", l)
}
var arr []*KeyValue
- if l := c.GetAll("/a/b/c/", &arr); l != 2 || (arr[0].Version != 1 && arr[1].Version != 1) {
- t.Fatalf("TestKvCache GetAll() failed, %d, %v", l, arr)
+ if l := c.GetPrefix("/a/b/c/", &arr); l != 2 || (arr[0].Version != 1 && arr[1].Version != 1) {
+ t.Fatalf("TestKvCache GetPrefix() failed, %d, %v", l, arr)
}
l, b := -1, false
@@ -134,7 +166,12 @@ func TestKvCache_Get(t *testing.T) {
c.Remove("/")
c.Remove("/a/b/c/d/e/2")
c.Remove("/a/b/d/d/f/3")
- if l := c.Size(); l != 2 {
- t.Fatalf("TestKvCache Size() failed, %d", l)
+ if l := c.GetAll(nil); l != 2 {
+ t.Fatalf("TestKvCache GetAll() failed, %d", l)
+ }
+
+ c.Put("/a/b/c/d/e/1", &KeyValue{Version: 2})
+ if kv := c.Get("/a/b/c/d/e/1"); kv == nil || kv.Version != 2 {
+ t.Fatalf("TestKvCache Put() failed, %v", kv)
}
}
diff --git a/server/core/backend/cacher_kv.go b/server/core/backend/cacher_kv.go
index 3d8a793..9be17aa 100644
--- a/server/core/backend/cacher_kv.go
+++ b/server/core/backend/cacher_kv.go
@@ -18,6 +18,7 @@ package backend
import (
"errors"
+ "fmt"
"github.com/apache/incubator-servicecomb-service-center/pkg/util"
"github.com/apache/incubator-servicecomb-service-center/server/core"
"github.com/apache/incubator-servicecomb-service-center/server/core/proto"
@@ -31,37 +32,39 @@ import (
type KvCacher struct {
Cfg *Config
- lastRev int64
- noEventCount int
+ latestListRev int64
+ noEventPeriods int
ready chan struct{}
- lw ListWatcher
+ lw ListWatch
mux sync.Mutex
once sync.Once
- cache *KvCache
+ cache Cache
goroutine *util.GoRoutine
}
+func (c *KvCacher) Config() *Config {
+ return c.Cfg
+}
+
func (c *KvCacher) needList() bool {
rev := c.lw.Revision()
- defer func() { c.lastRev = rev }()
-
if rev == 0 {
- c.noEventCount = 0
+ c.noEventPeriods = 0
return true
}
- if c.lastRev != rev {
- c.noEventCount = 0
+ if c.latestListRev != rev {
+ c.noEventPeriods = 0
return false
}
- c.noEventCount++
- if c.noEventCount < c.Cfg.NoEventMaxInterval {
+ c.noEventPeriods++
+ if c.Cfg.NoEventPeriods == 0 || c.noEventPeriods < c.Cfg.NoEventPeriods {
return false
}
util.Logger().Debugf("no events come in more then %s, need to list key %s, rev: %d",
- time.Duration(c.noEventCount)*c.Cfg.Timeout, c.Cfg.Prefix, rev)
- c.noEventCount = 0
+ time.Duration(c.noEventPeriods)*c.Cfg.Timeout, c.Cfg.Key, rev)
+ c.noEventPeriods = 0
return true
}
@@ -70,24 +73,28 @@ func (c *KvCacher) doList(cfg ListWatchConfig) error {
if err != nil {
return err
}
+ c.latestListRev = c.lw.Revision()
kvs := resp.Kvs
start := time.Now()
evts := c.filter(c.lw.Revision(), kvs)
if ec, kc := len(evts), len(kvs); c.Cfg.DeferHandler != nil && ec == 0 && kc != 0 &&
c.Cfg.DeferHandler.Reset() {
- util.Logger().Warnf(nil, "most of the protected data(%d/%d) are recovered", kc, c.cache.Size())
+ util.Logger().Warnf(nil, "most of the protected data(%d/%d) are recovered",
+ kc, c.cache.GetAll(nil))
}
c.sync(evts)
util.LogDebugOrWarnf(start, "finish to cache key %s, %d items, rev: %d",
- c.Cfg.Prefix, len(kvs), c.lw.Revision())
+ c.Cfg.Key, len(kvs), c.lw.Revision())
return nil
}
func (c *KvCacher) doWatch(cfg ListWatchConfig) error {
- watcher := c.lw.Watch(cfg)
- return c.handleWatcher(watcher)
+ if watcher := c.lw.Watch(cfg); watcher != nil {
+ return c.handleWatcher(watcher)
+ }
+ return fmt.Errorf("handle a nil watcher")
}
func (c *KvCacher) ListAndWatch(ctx context.Context) error {
@@ -99,7 +106,10 @@ func (c *KvCacher) ListAndWatch(ctx context.Context) error {
Context: ctx,
}
if c.needList() {
- c.doList(cfg)
+ if err := c.doList(cfg); err != nil && !c.IsReady() {
+ // cacher is not ready, so it need to retry util the cache is created
+ return err
+ }
}
util.SafeCloseChan(c.ready)
@@ -107,7 +117,7 @@ func (c *KvCacher) ListAndWatch(ctx context.Context) error {
return c.doWatch(cfg)
}
-func (c *KvCacher) handleWatcher(watcher *Watcher) error {
+func (c *KvCacher) handleWatcher(watcher Watcher) error {
defer watcher.Stop()
for resp := range watcher.EventBus() {
if resp == nil {
@@ -115,9 +125,10 @@ func (c *KvCacher) handleWatcher(watcher *Watcher) error {
}
start := time.Now()
+ rev := resp.Revision
evts := make([]KvEvent, 0, len(resp.Kvs))
for _, kv := range resp.Kvs {
- evt := KvEvent{Prefix: c.lw.Prefix, Revision: kv.ModRevision}
+ evt := KvEvent{Prefix: c.Cfg.Key, Revision: kv.ModRevision}
switch {
case resp.Action == registry.Put && kv.Version == 1:
evt.Type, evt.KV = proto.EVT_CREATE, c.doParse(kv)
@@ -142,7 +153,7 @@ func (c *KvCacher) handleWatcher(watcher *Watcher) error {
}
c.sync(evts)
util.LogDebugOrWarnf(start, "finish to handle %d events, prefix: %s, rev: %d",
- len(evts), c.Cfg.Prefix, c.lw.Revision())
+ len(evts), c.Cfg.Key, rev)
}
return nil
}
@@ -240,7 +251,7 @@ func (c *KvCacher) filterDelete(newStore map[string]*mvccpb.KeyValue,
block[i] = KvEvent{
Revision: rev,
Type: proto.EVT_DELETE,
- Prefix: c.Cfg.Prefix,
+ Prefix: c.Cfg.Key,
KV: v,
}
i++
@@ -272,7 +283,7 @@ func (c *KvCacher) filterCreateOrUpdate(newStore map[string]*mvccpb.KeyValue,
block[i] = KvEvent{
Revision: rev,
Type: proto.EVT_CREATE,
- Prefix: c.Cfg.Prefix,
+ Prefix: c.Cfg.Key,
KV: kv,
}
i++
@@ -294,7 +305,7 @@ func (c *KvCacher) filterCreateOrUpdate(newStore map[string]*mvccpb.KeyValue,
block[i] = KvEvent{
Revision: rev,
Type: proto.EVT_UPDATE,
- Prefix: c.Cfg.Prefix,
+ Prefix: c.Cfg.Key,
KV: kv,
}
i++
@@ -447,8 +458,7 @@ func (c *KvCacher) IsReady() bool {
}
func (c *KvCacher) reportMetrics(ctx context.Context) {
- if !core.ServerInfo.Config.EnablePProf ||
- !core.ServerInfo.Config.EnableCache {
+ if !core.ServerInfo.Config.EnablePProf {
return
}
timer := time.NewTimer(DEFAULT_METRICS_INTERVAL)
@@ -458,8 +468,7 @@ func (c *KvCacher) reportMetrics(ctx context.Context) {
case <-ctx.Done():
return
case <-timer.C:
- c.cache.ReportMetrics()
-
+ ReportCacheSize(c.cache.Name(), "raw", c.cache.Size())
timer.Reset(DEFAULT_METRICS_INTERVAL)
}
}
@@ -469,9 +478,9 @@ func NewKvCacher(name string, cfg *Config) *KvCacher {
cacher := &KvCacher{
Cfg: cfg,
ready: make(chan struct{}),
- lw: ListWatcher{
+ lw: &innerListWatch{
Client: Registry(),
- Prefix: cfg.Prefix,
+ Prefix: cfg.Key,
},
goroutine: util.NewGo(context.Background()),
}
diff --git a/server/core/backend/cacher_kv_test.go b/server/core/backend/cacher_kv_test.go
new file mode 100644
index 0000000..82455ec
--- /dev/null
+++ b/server/core/backend/cacher_kv_test.go
@@ -0,0 +1,340 @@
+/*
+ * 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 backend
+
+import (
+ "github.com/apache/incubator-servicecomb-service-center/pkg/util"
+ "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
+ "github.com/apache/incubator-servicecomb-service-center/server/infra/registry"
+ "github.com/coreos/etcd/mvcc/mvccpb"
+ "golang.org/x/net/context"
+ "strconv"
+ "testing"
+)
+
+type mockCache struct {
+ *nullCache
+ Key string
+ KV *KeyValue
+}
+
+func (n *mockCache) Get(k string) *KeyValue {
+ if k == n.Key {
+ return n.KV
+ }
+ return nil
+}
+func (n *mockCache) GetPrefix(prefix string, arr *[]*KeyValue) int {
+ if prefix == n.Key {
+ if arr != nil {
+ *arr = append(*arr, n.KV)
+ }
+ return 1
+ }
+ return 0
+}
+func (n *mockCache) ForEach(iter func(k string, v *KeyValue) (next bool)) {
+ iter(n.Key, n.KV)
+}
+func (n *mockCache) Put(k string, v *KeyValue) {
+ n.Key = k
+ n.KV = v
+}
+func (n *mockCache) Remove(k string) {
+ if k == n.Key {
+ n.Key = ""
+ n.KV = nil
+ }
+}
+
+func TestNewKvCacher(t *testing.T) {
+ w := &mockWatcher{}
+ lw := &mockListWatch{
+ Bus: make(chan *registry.PluginResponse, 100),
+ }
+ w.lw = lw
+
+ cr := &KvCacher{
+ Cfg: Configure(),
+ ready: make(chan struct{}),
+ lw: lw,
+ goroutine: util.NewGo(context.Background()),
+ cache: &mockCache{},
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+
+ // case: cause list internal error
+ cr.refresh(ctx)
+ if cr.IsReady() {
+ t.Fatalf("TestNewKvCacher failed")
+ }
+
+ // prepare data
+ var evt KvEvent
+ cr = &KvCacher{
+ Cfg: Configure().
+ WithNoEventPeriods(0).
+ WithEventFunc(func(e KvEvent) {
+ evt = e
+ }),
+ ready: make(chan struct{}),
+ lw: lw,
+ goroutine: util.NewGo(context.Background()),
+ cache: &mockCache{},
+ }
+
+ lw.Watcher = w
+ data := &mvccpb.KeyValue{Key: []byte("ka"), Value: []byte("va"), Version: 1, ModRevision: 2}
+ test := ®istry.PluginResponse{
+ Action: registry.Put,
+ Revision: 3,
+ Kvs: []*mvccpb.KeyValue{data}}
+
+ // case: list 1 resp and watch 0 event
+ cr.cache.Remove("ka")
+ lw.ListResponse = test
+ lw.Bus <- nil
+
+ cr.refresh(ctx)
+ // check ready
+ if !cr.IsReady() {
+ t.Fatalf("TestNewKvCacher failed")
+ }
+ // check event
+ if evt.Type != proto.EVT_INIT || evt.Revision != 3 || evt.KV.ModRevision != 2 || string(evt.KV.Key) != "ka" || string(evt.KV.Value.([]byte)) != "va" {
+ t.Fatalf("TestNewKvCacher failed, %v", evt)
+ }
+ // check cache
+ kv := cr.cache.Get("ka")
+ if kv == nil || kv.ModRevision != 2 || string(kv.Key) != "ka" || string(kv.Value.([]byte)) != "va" {
+ t.Fatalf("TestNewKvCacher failed")
+ }
+
+ test.Revision = 4
+ data.ModRevision = 3
+
+ // case: re-list and should be no event
+ lw.Bus <- nil
+ evt.KV = nil
+ cr.refresh(ctx)
+ if evt.KV != nil {
+ t.Fatalf("TestNewKvCacher failed")
+ }
+ // check cache
+ kv = cr.cache.Get("ka")
+ if kv == nil || kv.ModRevision != 2 || string(kv.Key) != "ka" || string(kv.Value.([]byte)) != "va" {
+ t.Fatalf("TestNewKvCacher failed")
+ }
+
+ // case re-list and over no event times
+ lw.Bus <- nil
+ evt.KV = nil
+ old := *cr.Cfg
+ cr.Cfg.WithNoEventPeriods(1)
+ cr.refresh(ctx)
+ // check event
+ if evt.Type != proto.EVT_UPDATE || evt.Revision != 4 || evt.KV.ModRevision != 3 || string(evt.KV.Key) != "ka" || string(evt.KV.Value.([]byte)) != "va" {
+ t.Fatalf("TestNewKvCacher failed, %v", evt)
+ }
+ // check cache
+ kv = cr.cache.Get("ka")
+ if kv == nil || kv.ModRevision != 3 || string(kv.Key) != "ka" || string(kv.Value.([]byte)) != "va" {
+ t.Fatalf("TestNewKvCacher failed")
+ }
+
+ lw.ListResponse = ®istry.PluginResponse{Revision: 5}
+ lw.Bus <- nil
+ evt.KV = nil
+ cr.refresh(ctx)
+ *cr.Cfg = old
+ // check event
+ if evt.Type != proto.EVT_DELETE || evt.Revision != 5 || evt.KV.ModRevision != 3 || string(evt.KV.Key) != "ka" || string(evt.KV.Value.([]byte)) != "va" {
+ t.Fatalf("TestNewKvCacher failed, %v", evt)
+ }
+ // check cache
+ kv = cr.cache.Get("ka")
+ if kv != nil {
+ t.Fatalf("TestNewKvCacher failed")
+ }
+
+ // case: no list and watch 1 event
+ test.Revision = 6
+ data.ModRevision = 5
+ lw.Bus <- test
+ lw.Bus <- nil
+
+ cr.refresh(ctx)
+ // check event
+ if evt.Type != proto.EVT_CREATE || evt.Revision != 5 || evt.KV.ModRevision != 5 || string(evt.KV.Key) != "ka" || string(evt.KV.Value.([]byte)) != "va" {
+ t.Fatalf("TestNewKvCacher failed, %v", evt)
+ }
+ // check cache
+ kv = cr.cache.Get("ka")
+ if kv == nil || kv.ModRevision != 5 || string(kv.Key) != "ka" || string(kv.Value.([]byte)) != "va" {
+ t.Fatalf("TestNewKvCacher failed")
+ }
+
+ test.Revision = 7
+ data.Version = 2
+ data.ModRevision = 6
+ lw.Bus <- test
+ lw.Bus <- nil
+
+ cr.refresh(ctx)
+ // check event
+ if evt.Type != proto.EVT_UPDATE || evt.Revision != 6 || evt.KV.ModRevision != 6 || string(evt.KV.Key) != "ka" || string(evt.KV.Value.([]byte)) != "va" {
+ t.Fatalf("TestNewKvCacher failed, %v", evt)
+ }
+ // check cache
+ kv = cr.cache.Get("ka")
+ if kv == nil || kv.ModRevision != 6 || string(kv.Key) != "ka" || string(kv.Value.([]byte)) != "va" {
+ t.Fatalf("TestNewKvCacher failed")
+ }
+
+ test.Revision = 8
+ test.Action = registry.Delete
+ data.Version = 0
+ data.ModRevision = 6
+ lw.Bus <- test
+ lw.Bus <- nil
+
+ cr.refresh(ctx)
+ // check event
+ if evt.Type != proto.EVT_DELETE || evt.Revision != 6 || evt.KV.ModRevision != 6 || string(evt.KV.Key) != "ka" || string(evt.KV.Value.([]byte)) != "va" {
+ t.Fatalf("TestNewKvCacher failed, %v", evt)
+ }
+ // check cache
+ kv = cr.cache.Get("ka")
+ if kv != nil {
+ t.Fatalf("TestNewKvCacher failed")
+ }
+
+ // case: list 1 item and watch no event
+ lw.Rev = 0
+ test.Revision = 9
+ data.Version = 1
+ data.ModRevision = 1
+ lw.ListResponse = test
+ lw.Bus <- nil
+ evt.KV = nil
+ cr.refresh(ctx)
+ // check event
+ if evt.Type != proto.EVT_CREATE || evt.Revision != 9 || evt.KV.ModRevision != 1 || string(evt.KV.Key) != "ka" || string(evt.KV.Value.([]byte)) != "va" {
+ t.Fatalf("TestNewKvCacher failed, %v", evt)
+ }
+ // check cache
+ kv = cr.cache.Get("ka")
+ if kv == nil || kv.ModRevision != 1 || string(kv.Key) != "ka" || string(kv.Value.([]byte)) != "va" {
+ t.Fatalf("TestNewKvCacher failed")
+ }
+
+ // case: caught delete event but value is nil
+ test.Revision = 10
+ test.Action = registry.Delete
+ data.Version = 0
+ data.ModRevision = 1
+ data.Value = nil
+ lw.Bus <- test
+ lw.Bus <- nil
+
+ cr.refresh(ctx)
+ data.Value = []byte("va")
+ // check event
+ if evt.Type != proto.EVT_DELETE || evt.Revision != 1 || evt.KV.ModRevision != 1 || string(evt.KV.Key) != "ka" || string(evt.KV.Value.([]byte)) != "va" {
+ t.Fatalf("TestNewKvCacher failed, %v", evt)
+ }
+ // check cache
+ kv = cr.cache.Get("ka")
+ if kv != nil {
+ t.Fatalf("TestNewKvCacher failed")
+ }
+
+ // case: parse failed
+ lw.Rev = 0
+ test.Revision = 1
+ data.Version = 1
+ data.ModRevision = 1
+ lw.ListResponse = test
+ lw.Bus <- nil
+ evt.KV = nil
+ old = *cr.Cfg
+ cr.Cfg.WithParser(MapParser)
+ cr.refresh(ctx)
+ // check event
+ if evt.KV != nil {
+ t.Fatalf("TestNewKvCacher failed, %v", evt)
+ }
+ // check cache
+ kv = cr.cache.Get("ka")
+ if kv != nil {
+ t.Fatalf("TestNewKvCacher failed")
+ }
+
+ lw.ListResponse = test
+ lw.Bus <- test
+ lw.Bus <- nil
+ cr.refresh(ctx)
+ *cr.Cfg = old
+ // check event
+ if evt.KV != nil {
+ t.Fatalf("TestNewKvCacher failed, %v", evt)
+ }
+ // check cache
+ kv = cr.cache.Get("ka")
+ if kv != nil {
+ t.Fatalf("TestNewKvCacher failed")
+ }
+
+ // case: list result is too large
+ var evts = make(map[string]KvEvent)
+ lw.Rev = 0
+ test.Revision = 3
+ test.Kvs = nil
+ for i := 0; i < eventBlockSize+1; i++ {
+ kv := *data
+ kv.Key = []byte(strconv.Itoa(i))
+ kv.Value = []byte(strconv.Itoa(i))
+ kv.Version = int64(i)
+ kv.ModRevision = int64(i)
+ test.Kvs = append(test.Kvs, &kv)
+ }
+ data.ModRevision = 2
+ test.Kvs = append(test.Kvs, data)
+ lw.ListResponse = test
+ lw.Bus <- nil
+ evt.KV = nil
+ old = *cr.Cfg
+ cr.Cfg.WithEventFunc(func(evt KvEvent) {
+ evts[string(evt.KV.Key)] = evt
+ })
+ cr.refresh(ctx)
+ // check all events
+ for i := 0; i < eventBlockSize+1; i++ {
+ s := strconv.Itoa(i)
+ if evt, ok := evts[s]; !ok || evt.Type != proto.EVT_CREATE || evt.KV.ModRevision != int64(i) || string(evt.KV.Value.([]byte)) != s {
+ t.Fatalf("TestNewKvCacher failed, %v", evt)
+ }
+ delete(evts, s)
+ }
+ evt = evts[string(data.Key)]
+ if len(evts) != 1 || evt.Type != proto.EVT_CREATE || evt.Revision != 3 || evt.KV.ModRevision != 2 {
+ t.Fatalf("TestNewKvCacher failed, %v %v", evts, evt)
+ }
+ delete(evts, string(data.Key))
+}
diff --git a/server/core/backend/common.go b/server/core/backend/common.go
index 1ae79d3..8c0eeee 100644
--- a/server/core/backend/common.go
+++ b/server/core/backend/common.go
@@ -17,6 +17,7 @@
package backend
import (
+ "errors"
apt "github.com/apache/incubator-servicecomb-service-center/server/core"
"strconv"
"time"
@@ -46,6 +47,11 @@ const TIME_FORMAT = "15:04:05.000"
const EVENT_BUS_MAX_SIZE = 1000
+// errors
+var (
+ ErrNoImpl = errors.New("no implement")
+)
+
var closedCh = make(chan struct{})
func init() {
@@ -56,7 +62,7 @@ type StoreType int
func (st StoreType) String() string {
if int(st) < 0 {
- return "NONEXIST"
+ return "TypeError"
}
if int(st) < len(TypeNames) {
return TypeNames[st]
@@ -64,7 +70,7 @@ func (st StoreType) String() string {
return "TYPE" + strconv.Itoa(int(st))
}
-const NONEXIST = StoreType(-1)
+const TypeError = StoreType(-1)
const (
DOMAIN StoreType = iota
@@ -105,49 +111,49 @@ var TypeNames = []string{
}
var TypeConfig = map[StoreType]*Config{
- SERVICE: DefaultConfig().WithPrefix(apt.GetServiceRootKey("")).
+ SERVICE: Configure().WithPrefix(apt.GetServiceRootKey("")).
WithInitSize(500).WithParser(ServiceParser),
- INSTANCE: DefaultConfig().WithPrefix(apt.GetInstanceRootKey("")).
+ INSTANCE: Configure().WithPrefix(apt.GetInstanceRootKey("")).
WithInitSize(1000).WithParser(InstanceParser).
WithDeferHandler(NewInstanceEventDeferHandler()),
- DOMAIN: DefaultConfig().WithPrefix(apt.GetDomainRootKey() + "/").
+ DOMAIN: Configure().WithPrefix(apt.GetDomainRootKey() + "/").
WithInitSize(100).WithParser(StringParser),
- SCHEMA: DefaultConfig().WithPrefix(apt.GetServiceSchemaRootKey("")).
+ SCHEMA: Configure().WithPrefix(apt.GetServiceSchemaRootKey("")).
WithInitSize(0),
- SCHEMA_SUMMARY: DefaultConfig().WithPrefix(apt.GetServiceSchemaSummaryRootKey("")).
+ SCHEMA_SUMMARY: Configure().WithPrefix(apt.GetServiceSchemaSummaryRootKey("")).
WithInitSize(100).WithParser(StringParser),
- RULE: DefaultConfig().WithPrefix(apt.GetServiceRuleRootKey("")).
+ RULE: Configure().WithPrefix(apt.GetServiceRuleRootKey("")).
WithInitSize(100).WithParser(RuleParser),
- LEASE: DefaultConfig().WithPrefix(apt.GetInstanceLeaseRootKey("")).
+ LEASE: Configure().WithPrefix(apt.GetInstanceLeaseRootKey("")).
WithInitSize(1000).WithParser(StringParser),
- SERVICE_INDEX: DefaultConfig().WithPrefix(apt.GetServiceIndexRootKey("")).
+ SERVICE_INDEX: Configure().WithPrefix(apt.GetServiceIndexRootKey("")).
WithInitSize(500).WithParser(StringParser),
- SERVICE_ALIAS: DefaultConfig().WithPrefix(apt.GetServiceAliasRootKey("")).
+ SERVICE_ALIAS: Configure().WithPrefix(apt.GetServiceAliasRootKey("")).
WithInitSize(100).WithParser(StringParser),
- SERVICE_TAG: DefaultConfig().WithPrefix(apt.GetServiceTagRootKey("")).
+ SERVICE_TAG: Configure().WithPrefix(apt.GetServiceTagRootKey("")).
WithInitSize(100).WithParser(MapParser),
- RULE_INDEX: DefaultConfig().WithPrefix(apt.GetServiceRuleIndexRootKey("")).
+ RULE_INDEX: Configure().WithPrefix(apt.GetServiceRuleIndexRootKey("")).
WithInitSize(100).WithParser(StringParser),
- DEPENDENCY: DefaultConfig().WithPrefix(apt.GetServiceDependencyRootKey("")).
+ DEPENDENCY: Configure().WithPrefix(apt.GetServiceDependencyRootKey("")).
WithInitSize(100),
- DEPENDENCY_RULE: DefaultConfig().WithPrefix(apt.GetServiceDependencyRuleRootKey("")).
+ DEPENDENCY_RULE: Configure().WithPrefix(apt.GetServiceDependencyRuleRootKey("")).
WithInitSize(100).WithParser(DependencyRuleParser),
- DEPENDENCY_QUEUE: DefaultConfig().WithPrefix(apt.GetServiceDependencyQueueRootKey("")).
+ DEPENDENCY_QUEUE: Configure().WithPrefix(apt.GetServiceDependencyQueueRootKey("")).
WithInitSize(100).WithParser(DependencyQueueParser),
- PROJECT: DefaultConfig().WithPrefix(apt.GetProjectRootKey("")).
+ PROJECT: Configure().WithPrefix(apt.GetProjectRootKey("")).
WithInitSize(100).WithParser(StringParser),
}
diff --git a/server/core/backend/config.go b/server/core/backend/config.go
index 32c2e41..7f1870f 100644
--- a/server/core/backend/config.go
+++ b/server/core/backend/config.go
@@ -23,23 +23,23 @@ import (
)
type Config struct {
- Prefix string
- InitSize int
- NoEventMaxInterval int
- Timeout time.Duration
- Period time.Duration
- DeferHandler DeferHandler
- OnEvent KvEventFunc
- Parser *Parser
+ Key string
+ InitSize int
+ NoEventPeriods int
+ Timeout time.Duration
+ Period time.Duration
+ DeferHandler DeferHandler
+ OnEvent KvEventFunc
+ Parser Parser
}
func (cfg *Config) String() string {
- return fmt.Sprintf("{prefix: %s, timeout: %s, period: %s}",
- cfg.Prefix, cfg.Timeout, cfg.Period)
+ return fmt.Sprintf("{key: %s, timeout: %s, period: %s}",
+ cfg.Key, cfg.Timeout, cfg.Period)
}
func (cfg *Config) WithPrefix(key string) *Config {
- cfg.Prefix = key
+ cfg.Key = key
return cfg
}
@@ -68,6 +68,11 @@ func (cfg *Config) WithEventFunc(f KvEventFunc) *Config {
return cfg
}
+func (cfg *Config) WithNoEventPeriods(p int) *Config {
+ cfg.NoEventPeriods = p
+ return cfg
+}
+
func (cfg *Config) AppendEventFunc(f KvEventFunc) *Config {
if prev := cfg.OnEvent; prev != nil {
next := f
@@ -80,19 +85,19 @@ func (cfg *Config) AppendEventFunc(f KvEventFunc) *Config {
return cfg
}
-func (cfg *Config) WithParser(parser *Parser) *Config {
+func (cfg *Config) WithParser(parser Parser) *Config {
cfg.Parser = parser
return cfg
}
-func DefaultConfig() *Config {
+func Configure() *Config {
return &Config{
- Prefix: "/",
- Timeout: DEFAULT_LISTWATCH_TIMEOUT,
- Period: time.Second,
- NoEventMaxInterval: DEFAULT_MAX_NO_EVENT_INTERVAL,
- InitSize: DEFAULT_CACHE_INIT_SIZE,
- Parser: BytesParser,
+ Key: "/",
+ Timeout: DEFAULT_LISTWATCH_TIMEOUT,
+ Period: time.Second,
+ NoEventPeriods: DEFAULT_MAX_NO_EVENT_INTERVAL,
+ InitSize: DEFAULT_CACHE_INIT_SIZE,
+ Parser: BytesParser,
}
}
diff --git a/server/core/backend/defer_instance.go b/server/core/backend/defer_instance.go
index fea9485..b89d511 100644
--- a/server/core/backend/defer_instance.go
+++ b/server/core/backend/defer_instance.go
@@ -104,17 +104,25 @@ func (iedh *InstanceEventDeferHandler) check(ctx context.Context) {
}
del := len(iedh.items)
- if del > 0 && !n {
- util.ResetTimer(t, DEFAULT_CHECK_WINDOW)
- n = true
+ if del == 0 {
+ continue
+ }
+
+ if iedh.enabled {
+ continue
}
- total := iedh.cache.Size()
- if !iedh.enabled && del > 0 && total > 5 && float64(del) >= float64(total)*iedh.Percent {
+ total := iedh.cache.GetAll(nil)
+ if total > 5 && float64(del) >= float64(total)*iedh.Percent {
iedh.enabled = true
util.Logger().Warnf(nil, "self preservation is enabled, caught %d/%d(>=%.0f%%) DELETE events",
del, total, iedh.Percent*100)
}
+
+ if !n {
+ util.ResetTimer(t, DEFAULT_CHECK_WINDOW)
+ n = true
+ }
case <-t.C:
n = false
diff --git a/server/core/backend/defer_test.go b/server/core/backend/defer_test.go
index 42a43e8..b8b3ebf 100644
--- a/server/core/backend/defer_test.go
+++ b/server/core/backend/defer_test.go
@@ -42,7 +42,7 @@ func TestInstanceEventDeferHandler_OnCondition(t *testing.T) {
func TestInstanceEventDeferHandler_HandleChan(t *testing.T) {
b := &pb.MicroServiceInstance{
HealthCheck: &pb.HealthCheck{
- Interval: 4,
+ Interval: 3,
Times: 0,
},
}
@@ -71,7 +71,7 @@ func TestInstanceEventDeferHandler_HandleChan(t *testing.T) {
Value: b,
}
- cache := NewKvCache("test", DefaultConfig())
+ cache := NewKvCache("test", Configure())
cache.Put("/1", kv1)
cache.Put("/2", kv2)
cache.Put("/3", kv3)
@@ -140,7 +140,7 @@ func TestInstanceEventDeferHandler_HandleChan(t *testing.T) {
getEvents(t, iedh)
- iedh.Percent = 0.8
+ iedh.Percent = 0.9
iedh.OnCondition(cache, evts1)
iedh.OnCondition(cache, evts2)
iedh.OnCondition(cache, evts3)
@@ -150,12 +150,12 @@ func TestInstanceEventDeferHandler_HandleChan(t *testing.T) {
func getEvents(t *testing.T, iedh *InstanceEventDeferHandler) {
fmt.Println(time.Now())
- c := time.After(3 * time.Second)
+ c := time.After(3500 * time.Millisecond)
var evt3 *KvEvent
for {
select {
case evt := <-iedh.HandleChan():
- fmt.Println(time.Now(), evt)
+ fmt.Println(time.Now(), evt.Type, string(evt.KV.Key))
if string(evt.KV.Key) == "/3" {
evt3 = &evt
if iedh.Percent == 0.01 && evt.Type == pb.EVT_DELETE {
@@ -164,8 +164,8 @@ func getEvents(t *testing.T, iedh *InstanceEventDeferHandler) {
}
continue
case <-c:
- if iedh.Percent == 0.8 && evt3 == nil {
- t.Fatalf(`TestInstanceEventDeferHandler_HandleChan with 80%% failed`)
+ if iedh.Percent == 0.9 && evt3 == nil {
+ t.Fatalf(`TestInstanceEventDeferHandler_HandleChan with 90%% failed`)
}
}
break
diff --git a/pkg/async/task.go b/server/core/backend/entity.go
similarity index 86%
copy from pkg/async/task.go
copy to server/core/backend/entity.go
index f4a884f..0d152e5 100644
--- a/pkg/async/task.go
+++ b/server/core/backend/entity.go
@@ -14,12 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package async
+package backend
-import "golang.org/x/net/context"
-
-type Task interface {
- Key() string
- Do(ctx context.Context) error
- Err() error
+type Entity interface {
+ Runnable
+ Indexer
+ Cacher
}
diff --git a/server/core/backend/entity_kv.go b/server/core/backend/entity_kv.go
new file mode 100644
index 0000000..4496137
--- /dev/null
+++ b/server/core/backend/entity_kv.go
@@ -0,0 +1,76 @@
+/*
+ * 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 backend
+
+import (
+ "github.com/apache/incubator-servicecomb-service-center/pkg/util"
+ "github.com/apache/incubator-servicecomb-service-center/server/core"
+ "sync"
+)
+
+var (
+ defaultKvEntity *KvEntity
+ newKvEntityOnce sync.Once
+)
+
+type KvEntity struct {
+ Cacher
+ Indexer
+}
+
+func (se *KvEntity) Run() {
+ if r, ok := se.Cacher.(Runnable); ok {
+ r.Run()
+ }
+}
+
+func (se *KvEntity) Stop() {
+ if r, ok := se.Cacher.(Runnable); ok {
+ r.Stop()
+ }
+}
+
+func (se *KvEntity) Ready() <-chan struct{} {
+ if r, ok := se.Cacher.(Runnable); ok {
+ return r.Ready()
+ }
+ return closedCh
+}
+
+func NewKvEntity(name string, cfg *Config) *KvEntity {
+ var entity KvEntity
+ switch {
+ case core.ServerInfo.Config.EnableCache && cfg.InitSize > 0:
+ entity.Cacher = NewKvCacher(name, cfg)
+ entity.Indexer = NewCacheIndexer(cfg, entity.Cache())
+ default:
+ util.Logger().Infof(
+ "core will not cache '%s' and ignore all events of it, cache enabled: %v, init size: %d",
+ name, core.ServerInfo.Config.EnableCache, cfg.InitSize)
+ entity.Indexer = NewCommonIndexer(cfg.Key, cfg.Parser)
+ }
+ return &entity
+}
+
+func DefaultKvEntity() *KvEntity {
+ newKvEntityOnce.Do(func() {
+ defaultKvEntity = &KvEntity{
+ Indexer: NewCommonIndexer(Configure().Key, BytesParser),
+ }
+ })
+ return defaultKvEntity
+}
diff --git a/main.go b/server/core/backend/entity_test.go
similarity index 57%
copy from main.go
copy to server/core/backend/entity_test.go
index 3d7ac97..1b6541f 100644
--- a/main.go
+++ b/server/core/backend/entity_test.go
@@ -14,22 +14,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package main
+package backend
-// plugins
-import _ "github.com/apache/incubator-servicecomb-service-center/server/bootstrap"
import (
- "github.com/apache/incubator-servicecomb-service-center/pkg/util"
- "github.com/apache/incubator-servicecomb-service-center/server"
- "github.com/apache/incubator-servicecomb-service-center/server/core/backend"
+ "github.com/apache/incubator-servicecomb-service-center/server/core"
+ "testing"
)
-func main() {
- server.Run()
+func TestNewKvEntity(t *testing.T) {
+ core.ServerInfo.Config.EnableCache = false
+ i := NewKvEntity("a", Configure().WithInitSize(1))
+ if _, ok := i.Indexer.(*CommonIndexer); !ok {
+ t.Fatalf("TestNewIndexer failed")
+ }
+ core.ServerInfo.Config.EnableCache = true
- util.GoCloseAndWait()
+ i.Run()
+ <-i.Ready()
+ i.Stop()
- backend.Registry().Close()
+ i = NewKvEntity("a", Configure().WithInitSize(0))
+ if _, ok := i.Indexer.(*CommonIndexer); !ok {
+ t.Fatalf("TestNewIndexer failed")
+ }
- util.Logger().Warn("service center exited", nil)
+ i = NewKvEntity("a", Configure())
+ if _, ok := i.Indexer.(*CacheIndexer); !ok {
+ t.Fatalf("TestNewIndexer failed")
+ }
+ if _, ok := i.Cacher.(*KvCacher); !ok {
+ t.Fatalf("TestNewIndexer failed")
+ }
}
diff --git a/server/core/backend/event_proxy.go b/server/core/backend/event_proxy.go
index 3b02287..f3c77cb 100644
--- a/server/core/backend/event_proxy.go
+++ b/server/core/backend/event_proxy.go
@@ -16,16 +16,18 @@
*/
package backend
-import "sync"
+import (
+ "sync"
+)
var (
- EventProxies map[StoreType]*KvEventProxy
+ eventProxies map[StoreType]*KvEventProxy
)
func init() {
- EventProxies = make(map[StoreType]*KvEventProxy, typeEnd)
+ eventProxies = make(map[StoreType]*KvEventProxy)
for i := StoreType(0); i != typeEnd; i++ {
- EventProxies[i] = NewEventProxy()
+ NewEventProxy(i)
}
}
@@ -48,10 +50,21 @@ func (h *KvEventProxy) OnEvent(evt KvEvent) {
h.lock.RUnlock()
}
-func NewEventProxy() *KvEventProxy {
- return &KvEventProxy{}
+func (h *KvEventProxy) injectConfig(t StoreType) *Config {
+ return TypeConfig[t].AppendEventFunc(h.OnEvent)
+}
+
+// unsafe
+func NewEventProxy(t StoreType) *KvEventProxy {
+ if proxy, ok := eventProxies[t]; ok {
+ return proxy
+ }
+ proxy := &KvEventProxy{}
+ proxy.injectConfig(t)
+ eventProxies[t] = proxy
+ return proxy
}
func EventProxy(t StoreType) *KvEventProxy {
- return EventProxies[t]
+ return eventProxies[t]
}
diff --git a/server/core/backend/extend_test.go b/server/core/backend/event_test.go
similarity index 58%
copy from server/core/backend/extend_test.go
copy to server/core/backend/event_test.go
index 3f1e1af..97632cb 100644
--- a/server/core/backend/extend_test.go
+++ b/server/core/backend/event_test.go
@@ -18,28 +18,35 @@ package backend
import "testing"
-type extend struct {
+type mockEventHandler struct {
+ StoreType StoreType
+ Evt KvEvent
}
-func (e *extend) Name() string {
- return "test"
+func (h *mockEventHandler) Type() StoreType {
+ return h.StoreType
}
-
-func (e *extend) Config() *Config {
- return DefaultConfig().WithPrefix("/test")
+func (h *mockEventHandler) OnEvent(evt KvEvent) {
+ h.Evt = evt
}
-func TestInstallType(t *testing.T) {
- id, err := InstallType(&extend{})
- if err != nil {
- t.Fatal(err)
+func TestAddEventHandler(t *testing.T) {
+ h := &mockEventHandler{StoreType: SERVICE}
+ evt := KvEvent{Revision: 1}
+
+ // case: add
+ proxy := EventProxy(SERVICE)
+ if nil == proxy {
+ t.Fatalf("TestAddEventHandler failed")
}
- if id == NONEXIST {
- t.Fatal(err)
+ if NewEventProxy(SERVICE) != proxy {
+ t.Fatalf("TestAddEventHandler failed")
}
- id, err = InstallType(&extend{})
- if id != NONEXIST || err == nil {
- t.Fatal("InstallType fail", err)
+ // case: normal
+ AddEventHandler(h)
+ proxy.OnEvent(evt)
+ if h.Evt != evt {
+ t.Fatalf("TestAddEventHandler failed")
}
}
diff --git a/server/core/backend/extend.go b/server/core/backend/extend.go
index dbc0cd1..83d16d5 100644
--- a/server/core/backend/extend.go
+++ b/server/core/backend/extend.go
@@ -16,12 +16,7 @@
*/
package backend
-import (
- "errors"
- "fmt"
-)
-
-type Entity interface {
+type Extension interface {
Name() string
Config() *Config
}
@@ -39,29 +34,7 @@ func (e *entity) Config() *Config {
return e.cfg
}
-func InstallType(e Entity) (id StoreType, err error) {
- if e == nil {
- return NONEXIST, errors.New("invalid parameter")
- }
- for _, n := range TypeNames {
- if n == e.Name() {
- return NONEXIST, fmt.Errorf("redeclare store type '%s'", n)
- }
- }
- for _, r := range TypeConfig {
- if r.Prefix == e.Config().Prefix {
- return NONEXIST, fmt.Errorf("redeclare store root '%s'", r)
- }
- }
-
- id = StoreType(len(TypeNames))
- TypeNames = append(TypeNames, e.Name())
- TypeConfig[id] = e.Config()
- EventProxies[id] = NewEventProxy()
- return
-}
-
-func NewEntity(name string, cfg *Config) Entity {
+func NewExtension(name string, cfg *Config) Extension {
return &entity{
name: name,
cfg: cfg,
diff --git a/server/core/backend/indexer.go b/server/core/backend/indexer.go
index 4f47a72..7333381 100644
--- a/server/core/backend/indexer.go
+++ b/server/core/backend/indexer.go
@@ -17,78 +17,10 @@
package backend
import (
- "fmt"
- "github.com/apache/incubator-servicecomb-service-center/pkg/util"
"github.com/apache/incubator-servicecomb-service-center/server/infra/registry"
"golang.org/x/net/context"
- "strings"
)
-type Response struct {
- Kvs []*KeyValue
- Count int64
-}
-
-func (pr *Response) MaxModRevision() (max int64) {
- for _, kv := range pr.Kvs {
- if max < kv.ModRevision {
- max = kv.ModRevision
- }
- }
- return
-}
-
type Indexer interface {
Search(ctx context.Context, opts ...registry.PluginOpOption) (*Response, error)
- Run()
- Stop()
- Ready() <-chan struct{}
-}
-
-type baseIndexer struct {
- Cfg *Config
-}
-
-func (i *baseIndexer) Search(ctx context.Context, opts ...registry.PluginOpOption) (r *Response, err error) {
- op := registry.OpGet(opts...)
- key := util.BytesToStringWithNoCopy(op.Key)
- if strings.Index(key, i.Cfg.Prefix) != 0 {
- return nil, fmt.Errorf("search %s mismatch pattern %s", key, i.Cfg.Prefix)
- }
-
- resp, err := Registry().Do(ctx, opts...)
- if err != nil {
- return nil, err
- }
-
- r = new(Response)
- r.Count = resp.Count
- if len(resp.Kvs) == 0 {
- return
- }
-
- kvs := make([]*KeyValue, 0, len(resp.Kvs))
- for _, src := range resp.Kvs {
- kv := new(KeyValue)
- if err = kv.From(i.Cfg.Parser, src); err != nil {
- continue
- }
- kvs = append(kvs, kv)
- }
- r.Kvs = kvs
- return
-}
-
-func (i *baseIndexer) Run() {
-}
-
-func (i *baseIndexer) Stop() {
-}
-
-func (i *baseIndexer) Ready() <-chan struct{} {
- return closedCh
-}
-
-func NewBaseIndexer(cfg *Config) (indexer *baseIndexer) {
- return &baseIndexer{Cfg: cfg}
}
diff --git a/server/core/backend/indexer.go b/server/core/backend/indexer_base.go
similarity index 58%
copy from server/core/backend/indexer.go
copy to server/core/backend/indexer_base.go
index 4f47a72..b2ba5bd 100644
--- a/server/core/backend/indexer.go
+++ b/server/core/backend/indexer_base.go
@@ -24,53 +24,48 @@ import (
"strings"
)
-type Response struct {
- Kvs []*KeyValue
- Count int64
+type CommonIndexer struct {
+ Client registry.Registry
+ Parser Parser
+ Root string
}
-func (pr *Response) MaxModRevision() (max int64) {
- for _, kv := range pr.Kvs {
- if max < kv.ModRevision {
- max = kv.ModRevision
- }
+func (i *CommonIndexer) CheckPrefix(key string) error {
+ if strings.Index(key, i.Root) != 0 {
+ return fmt.Errorf("search '%s' mismatch pattern %s", key, i.Root)
}
- return
+ return nil
}
-type Indexer interface {
- Search(ctx context.Context, opts ...registry.PluginOpOption) (*Response, error)
- Run()
- Stop()
- Ready() <-chan struct{}
-}
-
-type baseIndexer struct {
- Cfg *Config
-}
-
-func (i *baseIndexer) Search(ctx context.Context, opts ...registry.PluginOpOption) (r *Response, err error) {
+func (i *CommonIndexer) Search(ctx context.Context, opts ...registry.PluginOpOption) (r *Response, err error) {
op := registry.OpGet(opts...)
+
key := util.BytesToStringWithNoCopy(op.Key)
- if strings.Index(key, i.Cfg.Prefix) != 0 {
- return nil, fmt.Errorf("search %s mismatch pattern %s", key, i.Cfg.Prefix)
+
+ if err := i.CheckPrefix(key); err != nil {
+ return nil, err
}
- resp, err := Registry().Do(ctx, opts...)
+ resp, err := i.Client.Do(ctx, opts...)
if err != nil {
return nil, err
}
r = new(Response)
r.Count = resp.Count
- if len(resp.Kvs) == 0 {
+ if len(resp.Kvs) == 0 || op.CountOnly {
return
}
+ p := i.Parser
+ if op.KeyOnly {
+ p = nil
+ }
+
kvs := make([]*KeyValue, 0, len(resp.Kvs))
for _, src := range resp.Kvs {
kv := new(KeyValue)
- if err = kv.From(i.Cfg.Parser, src); err != nil {
+ if err = kv.From(p, src); err != nil {
continue
}
kvs = append(kvs, kv)
@@ -79,16 +74,6 @@ func (i *baseIndexer) Search(ctx context.Context, opts ...registry.PluginOpOptio
return
}
-func (i *baseIndexer) Run() {
-}
-
-func (i *baseIndexer) Stop() {
-}
-
-func (i *baseIndexer) Ready() <-chan struct{} {
- return closedCh
-}
-
-func NewBaseIndexer(cfg *Config) (indexer *baseIndexer) {
- return &baseIndexer{Cfg: cfg}
+func NewCommonIndexer(root string, p Parser) (indexer *CommonIndexer) {
+ return &CommonIndexer{Client: Registry(), Parser: p, Root: root}
}
diff --git a/server/core/backend/indexer_kv.go b/server/core/backend/indexer_kv.go
index 7cf2443..d1fb766 100644
--- a/server/core/backend/indexer_kv.go
+++ b/server/core/backend/indexer_kv.go
@@ -19,37 +19,36 @@ package backend
import (
"fmt"
"github.com/apache/incubator-servicecomb-service-center/pkg/util"
- "github.com/apache/incubator-servicecomb-service-center/server/core"
"github.com/apache/incubator-servicecomb-service-center/server/infra/registry"
"golang.org/x/net/context"
- "strings"
"sync"
"time"
)
type CacheIndexer struct {
- *baseIndexer
+ *CommonIndexer
- cacher Cacher
- lock sync.Mutex
- isClose bool
+ Cache Cache
+
+ lock sync.Mutex
}
func (i *CacheIndexer) Search(ctx context.Context, opts ...registry.PluginOpOption) (*Response, error) {
op := registry.OpGet(opts...)
+
key := util.BytesToStringWithNoCopy(op.Key)
- if strings.Index(key, i.baseIndexer.Cfg.Prefix) != 0 {
- return nil, fmt.Errorf("search %s mismatch %s pattern %s",
- key, i.cacher.Cache().Name(), i.baseIndexer.Cfg.Prefix)
- }
- if !core.ServerInfo.Config.EnableCache ||
+ if i.Cache == nil ||
op.Mode == registry.MODE_NO_CACHE ||
op.Revision > 0 ||
(op.Offset >= 0 && op.Limit > 0) {
- util.Logger().Debugf("search %s match special options, request etcd server, opts: %s",
- i.cacher.Cache().Name(), op)
- return i.baseIndexer.Search(ctx, opts...)
+ util.Logger().Debugf("search '%s' match special options, request etcd server, opts: %s",
+ key, op)
+ return i.CommonIndexer.Search(ctx, opts...)
+ }
+
+ if err := i.CheckPrefix(key); err != nil {
+ return nil, fmt.Errorf("%s, cache is '%s'", err.Error(), i.Cache.Name())
}
var resp *Response
@@ -63,9 +62,9 @@ func (i *CacheIndexer) Search(ctx context.Context, opts ...registry.PluginOpOpti
return resp, nil
}
- util.Logger().Debugf("can not find any key from %s cache with prefix, request etcd server, key: %s",
- i.cacher.Cache().Name(), key)
- return i.baseIndexer.Search(ctx, opts...)
+ util.Logger().Debugf("can not find any key from %s cache, request etcd server, key: %s",
+ i.Cache.Name(), key)
+ return i.CommonIndexer.Search(ctx, opts...)
}
func (i *CacheIndexer) search(op registry.PluginOp) *Response {
@@ -73,7 +72,7 @@ func (i *CacheIndexer) search(op registry.PluginOp) *Response {
key := util.BytesToStringWithNoCopy(op.Key)
- kv := i.cacher.Cache().Get(key)
+ kv := i.Cache.Get(key)
if kv != nil {
resp.Count = 1
}
@@ -90,61 +89,24 @@ func (i *CacheIndexer) searchByPrefix(op registry.PluginOp) *Response {
prefix := util.BytesToStringWithNoCopy(op.Key)
- resp.Count = int64(i.cacher.Cache().GetAll(prefix, nil))
+ resp.Count = int64(i.Cache.GetPrefix(prefix, nil))
if resp.Count == 0 || op.CountOnly {
return resp
}
t := time.Now()
kvs := make([]*KeyValue, 0, resp.Count)
- i.cacher.Cache().GetAll(prefix, &kvs)
+ i.Cache.GetPrefix(prefix, &kvs)
- util.LogNilOrWarnf(t, "too long to index data[%d] from cache '%s'", len(kvs), i.cacher.Cache().Name())
+ util.LogNilOrWarnf(t, "too long to index data[%d] from cache '%s'", len(kvs), i.Cache.Name())
resp.Kvs = kvs
return resp
}
-func (i *CacheIndexer) Run() {
- i.lock.Lock()
- if !i.isClose {
- i.lock.Unlock()
- return
- }
- i.isClose = false
- i.lock.Unlock()
-
- i.cacher.Run()
-}
-
-func (i *CacheIndexer) Stop() {
- i.lock.Lock()
- if i.isClose {
- i.lock.Unlock()
- return
- }
- i.isClose = true
- i.lock.Unlock()
-
- i.cacher.Stop()
-}
-
-func (i *CacheIndexer) Ready() <-chan struct{} {
- return i.cacher.Ready()
-}
-
-func NewCacheIndexer(name string, cfg *Config) (indexer *CacheIndexer) {
- indexer = &CacheIndexer{
- baseIndexer: NewBaseIndexer(cfg),
- cacher: NullCacher,
- isClose: true,
- }
-
- switch {
- case core.ServerInfo.Config.EnableCache && cfg.InitSize > 0:
- indexer.cacher = NewKvCacher(name, cfg)
- default:
- util.Logger().Infof("service center will not cache '%s'", name)
+func NewCacheIndexer(cfg *Config, cache Cache) *CacheIndexer {
+ return &CacheIndexer{
+ CommonIndexer: NewCommonIndexer(cfg.Key, cfg.Parser),
+ Cache: cache,
}
- return
}
diff --git a/server/core/backend/indexer_test.go b/server/core/backend/indexer_test.go
new file mode 100644
index 0000000..c38e727
--- /dev/null
+++ b/server/core/backend/indexer_test.go
@@ -0,0 +1,178 @@
+/*
+ * 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 backend
+
+import (
+ "context"
+ "github.com/apache/incubator-servicecomb-service-center/server/infra/registry"
+ "github.com/coreos/etcd/mvcc/mvccpb"
+ "testing"
+)
+
+func TestCommonIndexer_Search(t *testing.T) {
+ data := ®istry.PluginResponse{Revision: 1}
+ c := &mockRegistry{}
+ i := &CommonIndexer{Client: c, Root: "/", Parser: BytesParser}
+
+ // case: key does not contain prefix
+ resp, err := i.Search(context.Background(), registry.WithStrKey("a"))
+ if err == nil || resp != nil {
+ t.Fatalf("TestBaseIndexer_Search failed")
+ }
+
+ // case: client return err
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"))
+ if err == nil || resp != nil {
+ t.Fatalf("TestBaseIndexer_Search failed")
+ }
+
+ // case: kvs is empty
+ c.Response = data
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"))
+ if err != nil || resp == nil || resp.Count != 0 {
+ t.Fatalf("TestBaseIndexer_Search failed")
+ }
+
+ // case: parse error
+ data.Count = 2
+ data.Kvs = []*mvccpb.KeyValue{{Key: []byte("/a/b"), Value: []byte("abc")}, {Key: []byte("/a/c"), Value: []byte("{}")}}
+ old := i.Parser
+ i.Parser = MapParser
+ c.Response = data
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"))
+ if err != nil || resp == nil || resp.Count != 2 || len(resp.Kvs) != 1 {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+ i.Parser = old
+
+ // case: normal
+ data.Count = 2
+ data.Kvs = []*mvccpb.KeyValue{{Key: []byte("/a/b"), Value: []byte("abc")}, {Key: []byte("/a/c"), Value: []byte("{}")}}
+ c.Response = data
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"))
+ if err != nil || resp == nil || resp.Count != 2 || len(resp.Kvs) != 2 {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithKeyOnly())
+ if err != nil || resp == nil || resp.Count != 2 || len(resp.Kvs) != 2 {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithCountOnly())
+ if err != nil || resp == nil || resp.Count != 2 || len(resp.Kvs) != 0 {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+}
+
+func TestCacheIndexer_Search(t *testing.T) {
+ c := &mockCache{}
+ cli := &mockRegistry{Response: ®istry.PluginResponse{
+ Revision: 1,
+ Kvs: []*mvccpb.KeyValue{{Key: []byte("/a/b"), Value: []byte("abc")}},
+ Count: 1,
+ }}
+ i := &CacheIndexer{
+ CommonIndexer: &CommonIndexer{
+ Root: "/",
+ Client: cli,
+ },
+ Cache: c,
+ }
+
+ // case: key does not contain prefix
+ resp, err := i.Search(context.Background(), registry.WithStrKey("a"))
+ if err == nil || resp != nil {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+
+ // case: not match cache search remote
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"))
+ if err != nil || resp == nil || resp.Count != 1 || string(resp.Kvs[0].Key) != "/a/b" {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+
+ // no cache
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithNoCache())
+ if err != nil || resp == nil || resp.Count != 1 || string(resp.Kvs[0].Key) != "/a/b" {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+
+ // rev > 0 or paging
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithRev(1))
+ if err != nil || resp == nil || resp.Count != 1 || string(resp.Kvs[0].Key) != "/a/b" {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithOffset(0), registry.WithLimit(1))
+ if err != nil || resp == nil || resp.Count != 1 || string(resp.Kvs[0].Key) != "/a/b" {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+
+ // not match cache
+ c.Put("ka", &KeyValue{Key: []byte("ka"), Value: []byte("va"), Version: 1, ModRevision: 1})
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"))
+ if err != nil || resp == nil || resp.Count != 1 || string(resp.Kvs[0].Key) != "/a/b" {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithPrefix())
+ if err != nil || resp == nil || resp.Count != 1 || string(resp.Kvs[0].Key) != "/a/b" {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithCountOnly())
+ if err != nil || resp == nil || resp.Count != 1 {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+
+ // remote err
+ oldResp := cli.Response
+ cli.Response = nil
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"))
+ if err == nil || resp != nil {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+ cli.Response = oldResp
+
+ // case: use cache index
+ c.Put("/a", &KeyValue{Key: []byte("/a"), Value: []byte("va"), Version: 1, ModRevision: 1})
+
+ // exact match
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"))
+ if err != nil || resp == nil || resp.Count != 1 || string(resp.Kvs[0].Value.([]byte)) != "va" {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+ if resp.MaxModRevision() != 1 {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithCountOnly())
+ if err != nil || resp == nil || resp.Count != 1 || len(resp.Kvs) != 0 {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+
+ // prefix match
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithPrefix())
+ if err != nil || resp == nil || resp.Count != 1 || string(resp.Kvs[0].Value.([]byte)) != "va" {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a"), registry.WithPrefix(), registry.WithCountOnly())
+ if err != nil || resp == nil || resp.Count != 1 || len(resp.Kvs) != 0 {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+
+ // mismatch cache but cacheonly
+ resp, err = i.Search(context.Background(), registry.WithStrKey("/a/b"), registry.WithCacheOnly())
+ if err != nil || resp == nil || resp.Count != 0 || len(resp.Kvs) != 0 {
+ t.Fatalf("TestBaseIndexer_Search failed, %v, %v", err, resp)
+ }
+}
diff --git a/server/core/backend/lease.go b/server/core/backend/lease.go
index 89fcb2e..d3e7e8e 100644
--- a/server/core/backend/lease.go
+++ b/server/core/backend/lease.go
@@ -25,6 +25,8 @@ import (
)
type LeaseTask struct {
+ Client registry.Registry
+
key string
LeaseID int64
TTL int64
@@ -40,7 +42,7 @@ func (lat *LeaseTask) Key() string {
func (lat *LeaseTask) Do(ctx context.Context) (err error) {
recv, start := lat.ReceiveTime(), time.Now()
- lat.TTL, err = Registry().LeaseRenew(ctx, lat.LeaseID)
+ lat.TTL, err = lat.Client.LeaseRenew(ctx, lat.LeaseID)
if err != nil {
util.Logger().Errorf(err, "[%s]renew lease %d failed(recv: %s, send: %s), key %s",
time.Now().Sub(recv),
@@ -79,6 +81,7 @@ func (lat *LeaseTask) ReceiveTime() time.Time {
func NewLeaseAsyncTask(op registry.PluginOp) *LeaseTask {
now := time.Now().UTC()
return &LeaseTask{
+ Client: Registry(),
key: ToLeaseAsyncTaskKey(util.BytesToStringWithNoCopy(op.Key)),
LeaseID: op.Lease,
recvSec: now.Unix(),
diff --git a/server/plugin/infra/tracing/buildin/file_collector_test.go b/server/core/backend/lease_test.go
similarity index 55%
copy from server/plugin/infra/tracing/buildin/file_collector_test.go
copy to server/core/backend/lease_test.go
index 92956db..62e8a88 100644
--- a/server/plugin/infra/tracing/buildin/file_collector_test.go
+++ b/server/core/backend/lease_test.go
@@ -14,37 +14,36 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package buildin
+package backend
import (
- "github.com/apache/incubator-servicecomb-service-center/pkg/util"
- "github.com/openzipkin/zipkin-go-opentracing/thrift/gen-go/zipkincore"
- "golang.org/x/net/context"
- "os"
+ "context"
+ "fmt"
+ errorsEx "github.com/apache/incubator-servicecomb-service-center/pkg/errors"
"testing"
"time"
)
-func TestFileCollector_Collect(t *testing.T) {
- fc := &FileCollector{
- Fd: os.Stdout,
- Timeout: 1 * time.Second,
- Interval: 100 * time.Second,
- BatchSize: 2,
- c: make(chan *zipkincore.Span, 100),
- goroutine: util.NewGo(context.Background()),
+func TestLeaseTask_Do(t *testing.T) {
+ now := time.Now().UTC()
+ c := &mockRegistry{}
+ lt := &LeaseTask{
+ Client: c,
+ key: ToLeaseAsyncTaskKey("/a"),
+ LeaseID: 1,
+ recvSec: now.Unix(),
+ recvNsec: int64(now.Nanosecond()),
}
- defer func() {
- fc.Close()
- }()
- fc.Run()
- for i := 0; i < 10; i++ {
- err := fc.Collect(&zipkincore.Span{})
- if err != nil {
- t.Fatal(err)
- }
+ c.LeaseErr = errorsEx.InternalError("lease not found")
+ err := lt.Do(context.Background())
+ if err != nil || lt.Err() != nil {
+ t.Fatalf("TestLeaseTask_Do failed")
}
- <-time.After(time.Second)
+ c.LeaseErr = fmt.Errorf("network error")
+ err = lt.Do(context.Background())
+ if err == nil || lt.Err() == nil {
+ t.Fatalf("TestLeaseTask_Do failed")
+ }
}
diff --git a/server/core/backend/listwatch.go b/server/core/backend/listwatch.go
index 469a8d1..0286b2f 100644
--- a/server/core/backend/listwatch.go
+++ b/server/core/backend/listwatch.go
@@ -17,124 +17,15 @@
package backend
import (
- "fmt"
- "github.com/apache/incubator-servicecomb-service-center/pkg/util"
"github.com/apache/incubator-servicecomb-service-center/server/infra/registry"
"golang.org/x/net/context"
- "sync"
)
-type ListWatcher struct {
- Client registry.Registry
- Prefix string
-
- rev int64
-}
-
-func (lw *ListWatcher) List(op ListWatchConfig) (*registry.PluginResponse, error) {
- otCtx, _ := context.WithTimeout(op.Context, op.Timeout)
- resp, err := lw.Client.Do(otCtx, registry.WatchPrefixOpOptions(lw.Prefix)...)
- if err != nil {
- util.Logger().Errorf(err, "list prefix %s failed, current rev: %d", lw.Prefix, lw.Revision())
- return nil, err
- }
- lw.setRevision(resp.Revision)
- return resp, nil
-}
-
-func (lw *ListWatcher) Revision() int64 {
- return lw.rev
-}
-
-func (lw *ListWatcher) setRevision(rev int64) {
- lw.rev = rev
-}
-
-func (lw *ListWatcher) Watch(op ListWatchConfig) *Watcher {
- return newWatcher(lw, op)
-}
-
-func (lw *ListWatcher) doWatch(ctx context.Context, f func(*registry.PluginResponse)) error {
- rev := lw.Revision()
- opts := append(
- registry.WatchPrefixOpOptions(lw.Prefix),
- registry.WithRev(rev+1),
- registry.WithWatchCallback(
- func(message string, resp *registry.PluginResponse) error {
- if resp == nil || len(resp.Kvs) == 0 {
- return fmt.Errorf("unknown event %s, watch prefix %s", resp, lw.Prefix)
- }
-
- lw.setRevision(resp.Revision)
-
- f(resp)
- return nil
- }))
-
- err := lw.Client.Watch(ctx, opts...)
- if err != nil { // compact可能会导致watch失败 or message body size lager than 4MB
- util.Logger().Errorf(err, "watch prefix %s failed, start rev: %d+1->%d->0", lw.Prefix, rev, lw.Revision())
-
- lw.setRevision(0)
- f(nil)
- }
- return err
-}
-
-type Watcher struct {
- ListOps ListWatchConfig
- lw *ListWatcher
- bus chan *registry.PluginResponse
- stopCh chan struct{}
- stop bool
- mux sync.Mutex
-}
-
-func (w *Watcher) EventBus() <-chan *registry.PluginResponse {
- return w.bus
-}
-
-func (w *Watcher) process(_ context.Context) {
- stopCh := make(chan struct{})
- ctx, cancel := context.WithTimeout(w.ListOps.Context, w.ListOps.Timeout)
- util.Go(func(_ context.Context) {
- defer close(stopCh)
- w.lw.doWatch(ctx, w.sendEvent)
- })
-
- select {
- case <-stopCh:
- // timed out or exception
- w.Stop()
- case <-w.stopCh:
- cancel()
- }
-}
-
-func (w *Watcher) sendEvent(resp *registry.PluginResponse) {
- defer util.RecoverAndReport()
- w.bus <- resp
-}
-
-func (w *Watcher) Stop() {
- w.mux.Lock()
- if w.stop {
- w.mux.Unlock()
- return
- }
- w.stop = true
- close(w.stopCh)
- close(w.bus)
- w.mux.Unlock()
-}
-
-func newWatcher(lw *ListWatcher, listOps ListWatchConfig) *Watcher {
- w := &Watcher{
- ListOps: listOps,
- lw: lw,
- bus: make(chan *registry.PluginResponse, EVENT_BUS_MAX_SIZE),
- stopCh: make(chan struct{}),
- }
- util.Go(w.process)
- return w
+type ListWatch interface {
+ List(op ListWatchConfig) (*registry.PluginResponse, error)
+ // not support new multiple watchers
+ Watch(op ListWatchConfig) Watcher
+ //
+ DoWatch(ctx context.Context, f func(*registry.PluginResponse)) error
+ Revision() int64
}
diff --git a/server/core/backend/listwatch.go b/server/core/backend/listwatch_inner.go
similarity index 58%
copy from server/core/backend/listwatch.go
copy to server/core/backend/listwatch_inner.go
index 469a8d1..70b7234 100644
--- a/server/core/backend/listwatch.go
+++ b/server/core/backend/listwatch_inner.go
@@ -21,17 +21,16 @@ import (
"github.com/apache/incubator-servicecomb-service-center/pkg/util"
"github.com/apache/incubator-servicecomb-service-center/server/infra/registry"
"golang.org/x/net/context"
- "sync"
)
-type ListWatcher struct {
+type innerListWatch struct {
Client registry.Registry
Prefix string
rev int64
}
-func (lw *ListWatcher) List(op ListWatchConfig) (*registry.PluginResponse, error) {
+func (lw *innerListWatch) List(op ListWatchConfig) (*registry.PluginResponse, error) {
otCtx, _ := context.WithTimeout(op.Context, op.Timeout)
resp, err := lw.Client.Do(otCtx, registry.WatchPrefixOpOptions(lw.Prefix)...)
if err != nil {
@@ -42,19 +41,19 @@ func (lw *ListWatcher) List(op ListWatchConfig) (*registry.PluginResponse, error
return resp, nil
}
-func (lw *ListWatcher) Revision() int64 {
+func (lw *innerListWatch) Revision() int64 {
return lw.rev
}
-func (lw *ListWatcher) setRevision(rev int64) {
+func (lw *innerListWatch) setRevision(rev int64) {
lw.rev = rev
}
-func (lw *ListWatcher) Watch(op ListWatchConfig) *Watcher {
- return newWatcher(lw, op)
+func (lw *innerListWatch) Watch(op ListWatchConfig) Watcher {
+ return newInnerWatcher(lw, op)
}
-func (lw *ListWatcher) doWatch(ctx context.Context, f func(*registry.PluginResponse)) error {
+func (lw *innerListWatch) DoWatch(ctx context.Context, f func(*registry.PluginResponse)) error {
rev := lw.Revision()
opts := append(
registry.WatchPrefixOpOptions(lw.Prefix),
@@ -80,61 +79,3 @@ func (lw *ListWatcher) doWatch(ctx context.Context, f func(*registry.PluginRespo
}
return err
}
-
-type Watcher struct {
- ListOps ListWatchConfig
- lw *ListWatcher
- bus chan *registry.PluginResponse
- stopCh chan struct{}
- stop bool
- mux sync.Mutex
-}
-
-func (w *Watcher) EventBus() <-chan *registry.PluginResponse {
- return w.bus
-}
-
-func (w *Watcher) process(_ context.Context) {
- stopCh := make(chan struct{})
- ctx, cancel := context.WithTimeout(w.ListOps.Context, w.ListOps.Timeout)
- util.Go(func(_ context.Context) {
- defer close(stopCh)
- w.lw.doWatch(ctx, w.sendEvent)
- })
-
- select {
- case <-stopCh:
- // timed out or exception
- w.Stop()
- case <-w.stopCh:
- cancel()
- }
-}
-
-func (w *Watcher) sendEvent(resp *registry.PluginResponse) {
- defer util.RecoverAndReport()
- w.bus <- resp
-}
-
-func (w *Watcher) Stop() {
- w.mux.Lock()
- if w.stop {
- w.mux.Unlock()
- return
- }
- w.stop = true
- close(w.stopCh)
- close(w.bus)
- w.mux.Unlock()
-}
-
-func newWatcher(lw *ListWatcher, listOps ListWatchConfig) *Watcher {
- w := &Watcher{
- ListOps: listOps,
- lw: lw,
- bus: make(chan *registry.PluginResponse, EVENT_BUS_MAX_SIZE),
- stopCh: make(chan struct{}),
- }
- util.Go(w.process)
- return w
-}
diff --git a/server/core/backend/listwatch_test.go b/server/core/backend/listwatch_test.go
new file mode 100644
index 0000000..1a7b9a9
--- /dev/null
+++ b/server/core/backend/listwatch_test.go
@@ -0,0 +1,119 @@
+/*
+ * 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 backend
+
+import (
+ "fmt"
+ "github.com/apache/incubator-servicecomb-service-center/server/infra/registry"
+ "github.com/apache/incubator-servicecomb-service-center/server/plugin/infra/registry/buildin"
+ "github.com/coreos/etcd/mvcc/mvccpb"
+ "golang.org/x/net/context"
+ "testing"
+ "time"
+)
+
+type mockRegistry struct {
+ *buildin.BuildinRegistry
+ Response *registry.PluginResponse
+ LeaseErr error
+}
+
+func (c *mockRegistry) Do(ctx context.Context, opts ...registry.PluginOpOption) (*registry.PluginResponse, error) {
+ if c.Response == nil {
+ return nil, fmt.Errorf("error")
+ }
+ return c.Response, nil
+}
+func (c *mockRegistry) Watch(ctx context.Context, opts ...registry.PluginOpOption) error {
+ op := registry.OptionsToOp(opts...)
+ if c.Response == nil {
+ return fmt.Errorf("error")
+ }
+ resp := *c.Response
+ if len(c.Response.Kvs) > 0 {
+ resp.Revision = c.Response.Kvs[0].ModRevision
+ }
+ err := op.WatchCallback("ok", &resp)
+ if err != nil {
+ return err
+ }
+ <-ctx.Done()
+ return nil
+}
+func (c *mockRegistry) LeaseRenew(ctx context.Context, leaseID int64) (TTL int64, err error) {
+ if c.LeaseErr != nil {
+ return 0, c.LeaseErr
+ }
+ return 1, nil
+}
+
+func TestPrefixListWatch(t *testing.T) {
+ lw := &innerListWatch{
+ Client: &mockRegistry{},
+ Prefix: "a",
+ rev: 1,
+ }
+ resp, err := lw.List(ListWatchConfig{Timeout: time.Second, Context: context.Background()})
+ if resp != nil || err == nil || lw.Revision() != 1 {
+ t.Fatalf("TestPrefixListWatch failed")
+ }
+ w := lw.Watch(ListWatchConfig{Timeout: time.Second, Context: context.Background()})
+ resp = <-w.EventBus()
+ if resp != nil || lw.Revision() != 0 {
+ t.Fatalf("TestPrefixListWatch failed")
+ }
+ w.Stop()
+
+ test := ®istry.PluginResponse{
+ Revision: 2,
+ }
+ lw = &innerListWatch{
+ Client: &mockRegistry{Response: test},
+ Prefix: "a",
+ rev: 1,
+ }
+ resp, err = lw.List(ListWatchConfig{Timeout: time.Second, Context: context.Background()})
+ if resp == nil || err != nil || lw.Revision() != 2 {
+ t.Fatalf("TestPrefixListWatch failed")
+ }
+ w = lw.Watch(ListWatchConfig{Timeout: time.Second, Context: context.Background()})
+ resp = <-w.EventBus()
+ if resp != nil || lw.Revision() != 0 {
+ t.Fatalf("TestPrefixListWatch failed")
+ }
+ w.Stop()
+
+ test = ®istry.PluginResponse{
+ Kvs: []*mvccpb.KeyValue{{ModRevision: 3}},
+ Revision: 4,
+ }
+ lw = &innerListWatch{
+ Client: &mockRegistry{Response: test},
+ Prefix: "a",
+ rev: 1,
+ }
+ resp, err = lw.List(ListWatchConfig{Timeout: time.Second, Context: context.Background()})
+ if resp == nil || err != nil || lw.Revision() != 4 {
+ t.Fatalf("TestPrefixListWatch failed")
+ }
+ w = lw.Watch(ListWatchConfig{Timeout: time.Second, Context: context.Background()})
+ resp = <-w.EventBus()
+ if resp == nil || lw.Revision() != 3 {
+ t.Fatalf("TestPrefixListWatch failed")
+ }
+ w.Stop()
+}
diff --git a/server/core/backend/metrics.go b/server/core/backend/metrics.go
index 2423a7a..2b5f4e8 100644
--- a/server/core/backend/metrics.go
+++ b/server/core/backend/metrics.go
@@ -17,40 +17,31 @@
package backend
import (
- "github.com/apache/incubator-servicecomb-service-center/pkg/util"
- "github.com/apache/incubator-servicecomb-service-center/server/core"
+ "github.com/apache/incubator-servicecomb-service-center/server/metric"
"github.com/prometheus/client_golang/prometheus"
- "sync"
)
var (
cacheSizeGauge = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
- Namespace: "service_center",
+ Namespace: metric.FamilyName,
Subsystem: "local",
Name: "cache_size_bytes",
Help: "Local cache size summary of backend store",
}, []string{"instance", "resource", "type"})
)
-var (
- instance string
- once sync.Once
-)
-
func init() {
prometheus.MustRegister(cacheSizeGauge)
}
-func ReportCacheMetrics(resource, t string, obj interface{}) {
- if len(core.Instance.Endpoints) == 0 || len(resource) == 0 {
+func ReportCacheSize(resource, t string, s int) {
+ instance := metric.InstanceName()
+ if len(instance) == 0 || len(resource) == 0 {
// endpoints list will be empty when initializing
// resource may be empty when report SCHEMA
return
}
- once.Do(func() {
- instance, _ = util.ParseEndpoint(core.Instance.Endpoints[0])
- })
- cacheSizeGauge.WithLabelValues(instance, resource, t).Set(float64(util.Sizeof(obj)))
+ cacheSizeGauge.WithLabelValues(instance, resource, t).Set(float64(s))
}
diff --git a/server/core/backend/extend_test.go b/server/core/backend/metrics_test.go
similarity index 65%
copy from server/core/backend/extend_test.go
copy to server/core/backend/metrics_test.go
index 3f1e1af..60766e9 100644
--- a/server/core/backend/extend_test.go
+++ b/server/core/backend/metrics_test.go
@@ -16,30 +16,23 @@
*/
package backend
-import "testing"
+import (
+ "github.com/apache/incubator-servicecomb-service-center/server/metric"
+ "github.com/astaxie/beego"
+ "testing"
+)
-type extend struct {
+func init() {
+ beego.AppConfig.Set("httpaddr", "127.0.0.1")
}
-func (e *extend) Name() string {
- return "test"
-}
-
-func (e *extend) Config() *Config {
- return DefaultConfig().WithPrefix("/test")
-}
-
-func TestInstallType(t *testing.T) {
- id, err := InstallType(&extend{})
+func TestReportCacheSize(t *testing.T) {
+ ReportCacheSize("a", "b", 100)
+ err := metric.Gatherer.Collect()
if err != nil {
- t.Fatal(err)
- }
- if id == NONEXIST {
- t.Fatal(err)
+ t.Fatalf("TestReportCacheSize failed")
}
-
- id, err = InstallType(&extend{})
- if id != NONEXIST || err == nil {
- t.Fatal("InstallType fail", err)
+ if metric.Gatherer.Records.Get("local_cache_size_bytes") != 100 {
+ t.Fatalf("TestReportCacheSize failed")
}
}
diff --git a/server/core/backend/kv.go b/server/core/backend/model.go
similarity index 79%
rename from server/core/backend/kv.go
rename to server/core/backend/model.go
index f7b6688..2340dd9 100644
--- a/server/core/backend/kv.go
+++ b/server/core/backend/model.go
@@ -28,11 +28,28 @@ type KeyValue struct {
ModRevision int64
}
-func (kv *KeyValue) From(p *Parser, s *mvccpb.KeyValue) (err error) {
+func (kv *KeyValue) From(p Parser, s *mvccpb.KeyValue) (err error) {
kv.Key = s.Key
kv.Version = s.Version
kv.CreateRevision = s.CreateRevision
kv.ModRevision = s.ModRevision
+ if p == nil {
+ return
+ }
kv.Value, err = p.Unmarshal(s.Value)
return
}
+
+type Response struct {
+ Kvs []*KeyValue
+ Count int64
+}
+
+func (pr *Response) MaxModRevision() (max int64) {
+ for _, kv := range pr.Kvs {
+ if max < kv.ModRevision {
+ max = kv.ModRevision
+ }
+ }
+ return
+}
diff --git a/server/core/backend/parser.go b/server/core/backend/parser.go
index dff9a2f..26b291d 100644
--- a/server/core/backend/parser.go
+++ b/server/core/backend/parser.go
@@ -66,28 +66,32 @@ var (
}
)
-type Parser struct {
- c CreateValueFunc
- p ParseValueFunc
+type Parser interface {
+ Unmarshal(src []byte) (interface{}, error)
}
-func (p *Parser) Unmarshal(src []byte) (interface{}, error) {
- v := p.c()
- if err := p.p(src, &v); err != nil {
+type CommonParser struct {
+ NewFunc CreateValueFunc
+ FromFunc ParseValueFunc
+}
+
+func (p *CommonParser) Unmarshal(src []byte) (interface{}, error) {
+ v := p.NewFunc()
+ if err := p.FromFunc(src, &v); err != nil {
return nil, err
}
return v, nil
}
var (
... 5385 lines suppressed ...