marsevilspirit opened a new pull request, #2900:
URL: https://github.com/apache/dubbo-go/pull/2900
The purpose of this PR is to reduce the burden on the ProtocolConfig struct
by adding TripleConfig, which handles the config and options related only to
the Triple Protocol, thereby enhancing logical clarity.
For example, with the current code, if we want to configure the parameters
related to the Triple protocol keepalive, how should we write it:
```go
cli, err := client.NewClient(
client.WithClientURL("127.0.0.1:20000"),
client.WithClientProtocolTriple(),
client.WithKeepAliveInterval(10*time.Second),
client.WithKeepAliveTimeout(20*time.Second),
)
```
At first glance, it seems reasonable, but these two options can also be used
when I start other protocols, for example:
```go
cli, err := client.NewClient(
client.WithClientURL("127.0.0.1:20000"),
client.WithClientProtocolDubbo(),
client.WithKeepAliveInterval(10*time.Second),
client.WithKeepAliveTimeout(20*time.Second),
)
```
Well, this is unreasonable because **WithKeepAliveInterval** and
**WithKeepAliveTimeout** only take effect for the Triple protocol, yet they can
be used like this. This creates a learning cost for users, for example, users
are not clear that these two options only take effect for the Triple protocol,
and when they write other protocols, they mistakenly believe they will take
effect, but actually do not achieve the expected result, debugging for a long
time only to find out they only apply to the Triple protocol. Therefore, we
should enhance the specificity of options and impose restrictions at the API
level.
Moreover, the way parameters are passed and the structure above is also a
problem. The API above passes parameters and structures like this:
```go
// ProtocolConfig is a shared config for all protocols, it is inappropriate
to place parameters unique to Triple here,
// as the number of parameters grows, ProtocolConfig will become
increasingly bloated, and we need to find a way to solve this problem.
type ProtocolConfig struct {
...
MaxServerSendMsgSize string
MaxServerRecvMsgSize string
...
}
```
```go
// The same problem, as the number of parameters increases, the
URL configuration will become increasingly bloated,
// and the parameters in the URL are difficult to track and
extract, relying only on the key to extract one by one and judge whether it is
valid.
ivkURL := common.NewURLWithOptions(
...
common.WithParamsValue(constant.MaxServerSendMsgSize,
protocolConf.MaxServerSendMsgSize),
common.WithParamsValue(constant.MaxServerRecvMsgSize,
protocolConf.MaxServerRecvMsgSize),
...
)
// Parameters have to be extracted like this, which is too
inefficient, and the code duplication rate is too high, leading to complete
confusion with many parameters.
url.GetParam(constant.MaxServerRecvMsgSize, "")
url.GetParam(constant.MaxServerSendMsgSize, "")
...
```
I want to create a highly unified API for client and server, for example:
```go
[srv/cli], err := [server/client].New[Server/Client](
...
[server.client].With[Server/Client]Protocol(
protocol.With[XXX](),
protocol.With[Triple/...](
[triple/...].WithXXX(xxx...),
...
),
),
...
)
```
The actual API looks like this:
server:
```go
srv, err := server.NewServer(
server.WithServerProtocol(
protocol.WithPort(20000),
protocol.WithTriple(
triple.WithMaxServerRecvMsgSize("30mb"),
triple.WithMaxServerSendMsgSize("30mb"),
),
),
)
```
client:
```go
cli, err := client.NewClient(
client.WithClientURL("127.0.0.1:20000"),
client.WithClientProtocol(
protocol.WithTriple(
triple.WithKeepAliveInterval(30*time.Second),
triple.WithKeepAliveTimeout(30*time.Second),
),
),
)
```
This way, there will be no misuse of options that do not take effect.
How did I achieve interface unification?
Mainly by defining interfaces:
```go
// ClientOption is an option for the Client
type ClientOption interface {
applyToClient(*ClientOptions)
}
// ServerOption is an option for the Server
type ServerOption interface {
applyToServer(*ServerOptions)
}
// Option is a general option, meaning both Client and Server can use it
type Option interface {
ClientOption
ServerOption
}
```
How to implement shared options for client and server, I will take the
Triple Protocol as an example:
```go
type tripleOption struct {
triOpts triple.Options
}
// If the Client can call it, implement the applyToClient method
func (o *tripleOption) applyToClient(config *ClientOptions) {
config.ProtocolClient.TripleConfig = o.triOpts.Triple
}
// If the Server can call it, implement the applyToServer method
func (o *tripleOption) applyToServer(config *ServerOptions) {
config.Protocol.TripleConfig = o.triOpts.Triple
}
// The Triple Protocol must be a common option for both Server and Client
func WithTriple(opts ...triple.Option) Option {
triSrvOpts := triple.NewOptions(opts...)
return &tripleOption{
triOpts: *triSrvOpts,
}
}
```
After processing all options, just apply them collectively to
[Server/Client]:
```go
func New[Server/Client]Options(opts ...[Server/Client]Option)
*[Server/Client]Options {
defOpts := default[Server/Client]Options()
for _, opt := range opts {
// Apply here
opt.applyTo[Server/Client](defOpts)
}
if defOpts.ID == "" {
if defOpts.Protocol.Name == "" {
// should be the same as default value of
config.ProtocolConfig.Protocol
defOpts.ID = constant.TriProtocol
} else {
defOpts.ID = defOpts.Protocol.Name
}
}
return defOpts
}
```
How did I simplify parameter passing?
I created the TripleConfig struct and made modifications to the
ProtocolConfig struct:
```go
type TripleConfig struct {
// Parameters unique to the triple protocol are placed in this struct
KeepAliveInterval string
KeepAliveTimeout string
...
}
type ProtocolConfig struct {
...
TripleConfig *TripleConfig
...
}
```
The method of passing parameters is also very efficient:
```go
// Directly passing the TripleConfig struct
ivkURL := common.NewURLWithOptions(
...
common.WithAttribute(constant.TripleConfigKey,
protocolConf.TripleConfig),
...
)
// Extracting is also done directly by extracting the struct
// tripleConf contains all the parameters we want
var tripleConf *global.TripleConfig
tripleConfRaw, ok := url.GetAttribute(constant.TripleConfigKey)
if ok {
tripleConf = tripleConfRaw.(*global.TripleConfig)
}
```
Usage of TripleConfig in YAML files:
server:
```yaml
# dubbo server yaml configure file
dubbo:
registries:
demoZK:
protocol: zookeeper
timeout: 10s
address: 127.0.0.1:2181
protocols:
tripleProtocol:
name: tri
port: 20000
# triple is the tripleConfig
triple:
max-server-send-msg-size: 20mb
max-server-recv-msg-size: 20mb
provider:
services:
GreetTripleServer:
interface: com.apache.dubbo.sample.Greeter
```
client:
```yaml
# dubbo client yaml configure file
dubbo:
registries:
demoZK:
protocol: zookeeper
timeout: 3s
address: 127.0.0.1:2181
consumer:
references:
GreetServiceImpl:
# I know this configuration looks a bit strange, but this
protocol is for compatibility with the config package
# After solving the config package issue, the protocol-config may
be renamed to protocol
# Unifying the use of protocol configuration
# Here, the protocol is a string type, which makes me laugh XD
# For compatibility, we need version 4.0.0 to remove it
protocol: tri
protocol-config:
# triple is the tripleConfig
triple:
keep-alive-interval: 10s
keep-alive-timeout: 20s
interface: com.apache.dubbo.sample.Greeter
registry: demoZK
retries: 3
timeout: 3000
# The new version should look like this
dubbo:
registries:
demoZK:
protocol: zookeeper
timeout: 3s
address: 127.0.0.1:2181
consumer:
references:
GreetServiceImpl:
# Looks much better, doesn't it?
protocol:
name: tri
triple:
keep-alive-interval: 10s
keep-alive-timeout: 20s
interface: com.apache.dubbo.sample.Greeter
registry: demoZK
retries: 3
timeout: 3000
```
The benefits brought by this PR:
1. Greatly expands the flexibility of protocol options
2. Solves the problem of URLs becoming increasingly bloated
3. Addresses the issue of ProtocolConfig becoming increasingly bloated
4. Optimizes the usage of APIs related to Triple, further reducing the
learning cost for users
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]