-
Notifications
You must be signed in to change notification settings - Fork 14
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
Added a service Client interface and renamed the server interface #207
Added a service Client interface and renamed the server interface #207
Conversation
Here's the code health analysis summary for commits Analysis Summary
|
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.
Nice work!
There is a small snag though. The client interface must match the client-side implementation (in the generated _gorums.pb.go
files); specifically, the multicast and unicast types has an extra variadic opts
argument.
One way to enforce interface compliance is to declare a variable like this (could be in a separate file in the dev
folder):
// enforce interface compliance
var _ ZorumsServiceClient = (*Configuration)(nil)
This will give a compile error if the generated Configuration
object does not match the ZorumsServiceClient
interface.
I had to create two client interfaces, one for Configuration and one for Node, which looks like this: // Raft is the client-side Configuration API for the Raft Service
type RaftConfigurationClient interface {
RequestVote(ctx context.Context, in *raftpb.RequestVoteRequest) (resp *raftpb.RequestVoteResponse, err error)
AppendEntries(ctx context.Context, in *raftpb.AppendEntriesRequest, f func(*raftpb.AppendEntriesRequest, uint32) *raftpb.AppendEntriesRequest) (resp *raftpb.AppendEntriesQFResponse, err error)
}
// enforce interface compliance
var _ RaftConfigurationClient = (*Configuration)(nil)
// Raft is the client-side Node API for the Raft Service
type RaftNodeClient interface {
AppendEntries2(ctx context.Context, in *raftpb.AppendEntriesRequest) (resp *raftpb.AppendEntriesResponse, err error)
InstallSnapshot(ctx context.Context, in *commonpb.Snapshot) (resp *raftpb.InstallSnapshotResponse, err error)
CatchMeUp(ctx context.Context, in *raftpb.CatchMeUpRequest) (resp *raftpb.Empty, err error)
}
// enforce interface compliance
var _ RaftNodeClient = (*Node)(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.
Nice work again... We should avoid creating empty interfaces for both Node and Configuration.
|
||
var clientNodeInterface = ` | ||
{{$genFile := .GenFile}} | ||
{{range .Services -}} |
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.
See below for func definitions; use like this:
{{- range nodeOnlyServices .Services}}
{{$service := .GoName}} | ||
// {{$service}} is the client-side Node API for the {{$service}} Service | ||
type {{$service}}NodeClient interface { | ||
{{- range .Methods}} |
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.
And this:
{{- range nodeMethods .Methods}}
|
||
var clientConfigurationInterface = ` | ||
{{$genFile := .GenFile}} | ||
{{range .Services -}} |
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.
{{- range gorumsServices .Services}}
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.
(see implementations of the helper funcs below)
}, | ||
"isConfigurationCall": func(method *protogen.Method) bool { | ||
return hasMethodOption(method, gorums.E_Multicast, gorums.E_Quorumcall, gorums.E_Correctable, gorums.E_Async) | ||
}, | ||
"methods": func(services []*protogen.Service) (methods []*protogen.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.
Perhaps we can remove this one; it does not appear to be used. I don't remember why I added it, and it seems we are using .Methods
instead.
benchmark/benchmark_gorums.pb.go
Outdated
var _ BenchmarkConfigurationClient = (*Configuration)(nil) | ||
|
||
// Benchmark is the client-side Node API for the Benchmark Service | ||
type BenchmarkNodeClient interface { |
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.
We should avoid generating empty interfaces, and the corresponding interface compliance check if it is empty. See other comments for suggestions.
) | ||
|
||
// ZorumsService is the client-side Configuration API for the ZorumsService Service | ||
type ZorumsServiceConfigurationClient interface { |
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.
I wonder if we want such a long name... What do you think about just calling it ZorumsServiceClient
to align with gRPC's naming?
We can still use ZorumsServiceNodeClient
since that's more of a special case for Gorums.
{{- range .Methods}} | ||
{{- if isConfigurationCall .}} | ||
{{- if isOneway .}} | ||
{{- $customOut := customOut $genFile .}} |
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 one does not appear to be needed since $customOut
isn't used in this if-branch.
{{- range .Methods}} | ||
{{- if not (isConfigurationCall .)}} | ||
{{- if isOneway .}} | ||
{{- $customOut := customOut $genFile .}} |
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 one does not appear to be needed since $customOut
isn't used in this if-branch.
the qspecServices does not do what it was supposed to do. I decided to remove it since we need a QuorumSpec interface for the Configuration struct anyway. |
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.
A few more changes please. Mostly doc comment improvements and interface naming. And recall to regenerate.
|
||
var client = clientVariables + clientConfigurationInterface + clientNodeInterface | ||
|
||
// gorumsMethods returns all Gorums-specific methods, such as multicast, quorumcall, correctable, and async methods. |
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.
gorumsMethods --> configurationMethods
return s | ||
} | ||
|
||
// nodeOnlyServices returns all node-only services, such as services with only unicast and plain gRPC methods. |
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.
nodeOnlyServices? Or nodeServices.
return s | ||
} | ||
|
||
// gorumsServices returns all services that have Gorums methods. |
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.
configurationServices
{{- range configurationsServices .Services}} | ||
{{$service := .GoName}} | ||
// {{$service}} is the client-side Configuration API for the {{$service}} Service | ||
type {{$service}}ConfigurationClient interface { |
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.
// {{$service}}Client is the client interface for the {{$service}} service.
type {{$service}}Client interface {
I feel that having the Configuration
name be part of the interface name gives it a connotation to something we can configure.
{{$genFile := .GenFile}} | ||
{{- range nodeServices .Services}} | ||
{{$service := .GoName}} | ||
// {{$service}} is the client-side Node API for the {{$service}} Service |
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.
// {{$service}}NodeClient is the single node client interface for the {{$service}} service.
type {{$service}}NodeClient interface {
(only comment change)
I rewrote some of the comments and fixed the qspec template, now you could maybe even have multiple services without quorum calls. |
Example client interface:
The server interface would now look like this:
Fixes #178