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) {