You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by ti...@apache.org on 2020/03/02 09:01:54 UTC
[servicecomb-kie] branch master updated: #109 client支持指定revision (#108)
This is an automated email from the ASF dual-hosted git repository.
tianxiaoliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git
The following commit(s) were added to refs/heads/master by this push:
new 2720808 #109 client支持指定revision (#108)
2720808 is described below
commit 2720808ae136d483d42914397c6f3a0a7f9dfb23
Author: zhulijian <zh...@huawei.com>
AuthorDate: Mon Mar 2 17:01:46 2020 +0800
#109 client支持指定revision (#108)
* Improve client revision features
Signed-off-by: zhulijian <zh...@huawei.com>
* ut
---
client/client.go | 40 ++++++++++++++++++++++++++++------------
client/client_test.go | 24 ++++++++++++++++--------
client/options.go | 20 +++++++++++++++-----
3 files changed, 59 insertions(+), 25 deletions(-)
diff --git a/client/client.go b/client/client.go
index b70d465..422a537 100644
--- a/client/client.go
+++ b/client/client.go
@@ -25,6 +25,7 @@ import (
"fmt"
"net/http"
"net/url"
+ "strconv"
"strings"
"github.com/apache/servicecomb-kie/pkg/common"
@@ -57,7 +58,7 @@ type Client struct {
opts Config
cipher security.Cipher
c *httpclient.Requests
- CurrentRevision string
+ currentRevision int
}
//Config is the config of client
@@ -127,7 +128,7 @@ func (c *Client) Put(ctx context.Context, kv model.KVRequest, opts ...OpOption)
}
//Get get value of a key
-func (c *Client) Get(ctx context.Context, opts ...GetOption) (*model.KVResponse, error) {
+func (c *Client) Get(ctx context.Context, opts ...GetOption) (*model.KVResponse, int, error) {
options := GetOptions{}
for _, o := range opts {
o(&options)
@@ -135,12 +136,14 @@ func (c *Client) Get(ctx context.Context, opts ...GetOption) (*model.KVResponse,
if options.Project == "" {
options.Project = defaultProject
}
-
+ if options.Revision == "" {
+ options.Revision = strconv.Itoa(c.currentRevision)
+ }
var url string
if options.Key != "" {
- url = fmt.Sprintf("%s/%s/%s/%s/%s?revision=%s", c.opts.Endpoint, version, options.Project, APIPathKV, options.Key, c.CurrentRevision)
+ url = fmt.Sprintf("%s/%s/%s/%s/%s?revision=%s", c.opts.Endpoint, version, options.Project, APIPathKV, options.Key, options.Revision)
} else {
- url = fmt.Sprintf("%s/%s/%s/%s?revision=%s", c.opts.Endpoint, version, options.Project, APIPathKV, c.CurrentRevision)
+ url = fmt.Sprintf("%s/%s/%s/%s?revision=%s", c.opts.Endpoint, version, options.Project, APIPathKV, options.Revision)
}
if options.Wait != "" {
url = url + "&wait=" + options.Wait
@@ -158,31 +161,39 @@ func (c *Client) Get(ctx context.Context, opts ...GetOption) (*model.KVResponse,
h := http.Header{}
resp, err := c.c.Do(ctx, http.MethodGet, url, h, nil)
if err != nil {
- return nil, err
+ return nil, -1, err
+ }
+ responseRevision, err := strconv.Atoi(resp.Header.Get(common.HeaderRevision))
+ if err != nil {
+ responseRevision = -1
}
b := httputil.ReadBody(resp)
if resp.StatusCode != http.StatusOK {
if resp.StatusCode == http.StatusNotFound {
- return nil, ErrKeyNotExist
+ return nil, responseRevision, ErrKeyNotExist
}
if resp.StatusCode == http.StatusNotModified {
- return nil, ErrNoChanges
+ return nil, responseRevision, ErrNoChanges
}
openlogging.Error(MsgGetFailed, openlogging.WithTags(openlogging.Tags{
"k": options.Key,
"status": resp.Status,
"body": b,
}))
- return nil, fmt.Errorf(FmtGetFailed, options.Key, resp.Status, b)
+ return nil, responseRevision, fmt.Errorf(FmtGetFailed, options.Key, resp.Status, b)
+ } else if err != nil {
+ msg := fmt.Sprintf("get revision from response header failed when the request status is OK: %v", err)
+ openlogging.Error(msg)
+ return nil, responseRevision, fmt.Errorf(msg)
}
var kvs *model.KVResponse
err = json.Unmarshal(b, &kvs)
if err != nil {
openlogging.Error("unmarshal kv failed:" + err.Error())
- return nil, err
+ return nil, responseRevision, err
}
- c.CurrentRevision = resp.Header.Get(common.HeaderRevision)
- return kvs, nil
+ c.currentRevision = responseRevision
+ return kvs, responseRevision, nil
}
//Summary get value by labels
@@ -261,3 +272,8 @@ func (c *Client) Delete(ctx context.Context, kvID, labelID string, opts ...OpOpt
}
return nil
}
+
+//CurrentRevision return the current revision of kie, which is updated on the last get request
+func (c *Client) CurrentRevision() int {
+ return c.currentRevision
+}
diff --git a/client/client_test.go b/client/client_test.go
index b66a598..7c8fcd0 100644
--- a/client/client_test.go
+++ b/client/client_test.go
@@ -40,24 +40,32 @@ func TestClient_Put(t *testing.T) {
_, err := c.Put(context.TODO(), kv, WithProject("client_test"))
assert.NoError(t, err)
- kvs, _ := c.Get(context.TODO(),
+ kvs, responseRevision, _ := c.Get(context.TODO(),
WithKey("app.properties"),
WithGetProject("client_test"),
WithLabels(map[string]string{"service": "client"}))
assert.GreaterOrEqual(t, len(kvs.Data), 1)
- _, err = c.Get(context.TODO(),
+ _, _, err = c.Get(context.TODO(),
WithGetProject("client_test"),
- WithLabels(map[string]string{"service": "client"}))
+ WithLabels(map[string]string{"service": "client"}),
+ WithRevision(responseRevision))
assert.Equal(t, ErrNoChanges, err)
- _, err = c.Get(context.TODO(),
+ _, _, err = c.Get(context.TODO(),
+ WithGetProject("client_test"),
WithLabels(map[string]string{"service": "client"}))
assert.Error(t, err)
+ _, _, err = c.Get(context.TODO(),
+ WithGetProject("client_test"),
+ WithLabels(map[string]string{"service": "client"}),
+ WithRevision(c.CurrentRevision()-1))
+ assert.NoError(t, err)
+
t.Run("long polling,wait 10s,change value,should return result", func(t *testing.T) {
go func() {
- kvs, err = c.Get(context.TODO(),
+ kvs, _, err = c.Get(context.TODO(),
WithLabels(map[string]string{"service": "client"}),
WithGetProject("client_test"),
WithWait("10s"))
@@ -80,8 +88,8 @@ func TestClient_Put(t *testing.T) {
}
_, err := c.Put(context.TODO(), kv, WithProject("client_test"))
assert.NoError(t, err)
- t.Log(c.CurrentRevision)
- kvs, err = c.Get(context.TODO(),
+ t.Log(c.CurrentRevision())
+ kvs, _, err = c.Get(context.TODO(),
WithGetProject("client_test"),
WithLabels(map[string]string{"service": "client"}),
WithExact())
@@ -103,7 +111,7 @@ func TestClient_Delete(t *testing.T) {
kvBody.Labels["env"] = "client_test"
kv, err := c.Put(context.TODO(), kvBody, WithProject("client_test"))
assert.NoError(t, err)
- kvs, err := c.Get(context.TODO(),
+ kvs, _, err := c.Get(context.TODO(),
WithKey("time"),
WithGetProject("client_test"),
WithLabels(map[string]string{"env": "client_test"}))
diff --git a/client/options.go b/client/options.go
index 6b2b9a7..f450e33 100644
--- a/client/options.go
+++ b/client/options.go
@@ -17,6 +17,8 @@
package client
+import "strconv"
+
const (
defaultProject = "default"
)
@@ -29,11 +31,12 @@ type OpOption func(*OpOptions)
//GetOptions is the options of client func
type GetOptions struct {
- Labels []map[string]string
- Project string
- Key string
- Wait string
- Exact bool
+ Labels []map[string]string
+ Project string
+ Key string
+ Wait string
+ Exact bool
+ Revision string
}
//OpOptions is the options of client func
@@ -78,6 +81,13 @@ func WithKey(k string) GetOption {
}
}
+//WithRevision query keys with certain revision
+func WithRevision(revision int) GetOption {
+ return func(options *GetOptions) {
+ options.Revision = strconv.Itoa(revision)
+ }
+}
+
//WithProject set project to param
func WithProject(project string) OpOption {
return func(options *OpOptions) {