-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parse ServiceConfig JSON string #1515
Conversation
f539b14
to
04aa293
Compare
clientconn.go
Outdated
Method *string `json:"method,omitempty"` | ||
} | ||
|
||
func (j jsonName) Stringer() string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/Stringer()
/String()
?
Stringer
is the name of an interface with a String()
function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
clientconn.go
Outdated
res += "/" + *j.Service + "/" | ||
} | ||
if j.Method != nil { | ||
res += *j.Method |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If service == nil
, this function returns "method"
, is this right?
When searching in the map, we search for /service/method
first, then /service/
, but never for method
. Do we need to store the value in the map if service == nil
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right. change has been made to skip storing such method config.
clientconn.go
Outdated
return err | ||
} | ||
cc.scRaw = js | ||
var sc ServiceConfig |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sc := ServiceConfig {
 LB: rsc.LoadBalancingPolicy,
 Methods: make(map[string]MethodConfig),
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
clientconn.go
Outdated
|
||
// handleServiceConfig parses the service config string in JSON format to Go native | ||
// struct ServiceConfig, and store both the struct and the JSON string in ClientConn. | ||
func (cc *ClientConn) handleServiceConfig(js string) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move the all service config related code (structs and functions) to a new file service_config.go
and also add unit tests for the json parsing function.
Put all the parsing code in a function
func parseJsonServiceConfig(js string) (ServiceConfig, error)
In ClientConn
, you can do
if sc, err := parse(js); err == nil {
cc.mu.Lock()
cc.scRaw = js
cc.sc = sc
cc.mu.Unlock()
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
test/end2end_test.go
Outdated
@@ -1226,104 +1230,192 @@ func newDuration(b time.Duration) (a *time.Duration) { | |||
func TestServiceConfigGetMethodConfig(t *testing.T) { | |||
defer leakcheck.Check(t) | |||
for _, e := range listTestEnv() { | |||
testGetMethodConfig(t, e) | |||
if e.balancer == "roundrobin" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be OK to test service config with only one of the test envs. Then we don't need this wrapper function and loop.
Just start the test with
te := testServiceConfigSetup(t, tcpClearRREnv)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
test/end2end_test.go
Outdated
Methods: m, | ||
} | ||
ch <- sc | ||
scjs := `{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move the code around so the declaration of a variable is closed to where it's used?
You actually don't need this string variable if you don't need to check against it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
test/end2end_test.go
Outdated
// Make sure service config has been processed by grpc. | ||
mc := cc.GetMethodConfig("/grpc.testing.TestService/EmptyCall") | ||
for { | ||
if mc.WaitForReady == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for {
if cc.GetMethodConfig("/grpc.testing.TestService/EmptyCall").WaitForReady != nil {
break
}
time.Sleep(time.Millisecond)
}
Probably also add some timeout:
var processed bool
for i := 0; i < 1000; i++ {
if cc.GetMethodConfig("/grpc.testing.TestService/EmptyCall").WaitForReady != nil {
processed = true
break
}
time.Sleep(time.Millisecond)
}
if !processed {
t.Fatalf("service config is not processed by gRPC after 1 second")
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this code logic has been deleted in recent commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you forget to push some commits?
This code is still here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
clientconn.go
Outdated
// struct ServiceConfig, and store both the struct and the JSON string in ClientConn. | ||
func (cc *ClientConn) handleServiceConfig(js string) error { | ||
sc, err := parseServiceConfig(js) | ||
if err == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Return error early instead.
sc, err := parseServiceConfig(js)
if err != nil {
return err
}
cc.mu.Lock()
cc.scRaw = js
cc.sc = sc
cc.mu.Unlock()
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
rpc_util.go
Outdated
@@ -524,7 +524,7 @@ type MethodConfig struct { | |||
type ServiceConfig struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this struct to the new file, too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
service_config.go
Outdated
Method *string `json:"method,omitempty"` | ||
} | ||
|
||
func (j jsonName) String() (string, bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typically, String()
function only returns string
.
Rename this to getPath()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
service_config_test.go
Outdated
"name": [ | ||
{ | ||
"service": "foo", | ||
"method": "Bar" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation for this and some of the following tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still doesn't look right...
service_config_test.go
Outdated
) | ||
|
||
func TestParseLoadBalancer(t *testing.T) { | ||
defer leakcheck.Check(t) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leakcheck is unnecessary for tests like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
test/end2end_test.go
Outdated
// Make sure service config has been processed by grpc. | ||
mc := cc.GetMethodConfig("/grpc.testing.TestService/EmptyCall") | ||
for { | ||
if mc.WaitForReady == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you forget to push some commits?
This code is still here.
service_config.go
Outdated
MaxResponseMessageBytes *int `json:"maxResponseMessageBytes,omitempty"` | ||
} | ||
|
||
type jsonSC struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This struct is same as the real ServiceConfig
struct except for the second field. I prefer to not have this temporary struct, and reuse the existing structs.
json
does a partial parsing if the struct only contains part of the fields, so we could do Unmarshal
twice, first time for the service/method name, second time for the remaining configs. The second Unmarshal
can go directly to the existing MethodConfig
struct.
https://play.golang.org/p/GCSXcP1yQk
const testJSON = `{"name": [ {"service": "foo", "method": "bar"} ], "waitForReady": true}`
type jsonName struct {
Service *string `json:"service,omitempty"`
Method *string `json:"method,omitempty"`
}
type methodConfigName struct {
Name *[]jsonName
}
type MethodConfig struct {
WaitForReady *bool
Timeout *string
}
func main() {
buf := []byte(testJSON)
var mcn methodConfigName
err := json.Unmarshal(buf, &mcn) // for name only.
if err != nil {
panic(err.Error())
}
fmt.Printf("%+v\n", mcn)
var mc MethodConfig
err = json.Unmarshal(buf, &mc) // for everything other than name.
if err != nil {
panic(err.Error())
}
fmt.Printf("%+v\n", mc)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
filed names are different and go json package cannot handle it.
@@ -577,6 +579,7 @@ type ClientConn struct { | |||
|
|||
mu sync.RWMutex | |||
sc ServiceConfig | |||
scRaw string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Set this to ""
in scWatcher
? Just to be "consistent".
service_config_test.go
Outdated
"name": [ | ||
{ | ||
"service": "foo", | ||
"method": "Bar" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still doesn't look right...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
No description provided.