update design doc
This commit is contained in:
parent
18c4c4a2da
commit
dca67829b6
@ -10,7 +10,7 @@ goc build/install/run 会尽可能的模仿 go 原生的方式去处理参数。
|
|||||||
|
|
||||||
## 主要问题
|
## 主要问题
|
||||||
|
|
||||||
1. goc 使用 cobra 库来组织各个子命令。cobra 对 flag 处理采用的是 posix 风格(两个个短横线),和 go 的 flag 处理差异很大(一个短横线)。
|
1. goc 使用 cobra 库来组织各个子命令。cobra 对 flag 处理采用的是 posix 风格(两个短横线),和 go 的 flag 处理差异很大(一个短横线)。
|
||||||
2. go 命令中 args 和 flags 有着严格先后顺序。而 cobra 库对 flags 和 args 的位置没有要求。
|
2. go 命令中 args 和 flags 有着严格先后顺序。而 cobra 库对 flags 和 args 的位置没有要求。
|
||||||
3. 参数中 `[packages]` 有多种组合情况,会影响到插桩的起始位置。
|
3. 参数中 `[packages]` 有多种组合情况,会影响到插桩的起始位置。
|
||||||
4. goc 还有自己参数,且需要和**非** goc build/install/run 的子命令保持一致(两个短横线)。
|
4. goc 还有自己参数,且需要和**非** goc build/install/run 的子命令保持一致(两个短横线)。
|
49
doc/protocol.md
Normal file
49
doc/protocol.md
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# 通信协议设计
|
||||||
|
|
||||||
|
## 背景
|
||||||
|
|
||||||
|
v1 版本中,被插桩的服务会暴露一个 HTTP 接口,由 goc server 来访问获取覆盖率。
|
||||||
|
|
||||||
|
该方式要求被插桩的服务要有一个外界可访问的 ip + port。
|
||||||
|
|
||||||
|
如果被测服务躲在 NAT 网络下,该方式就不可行了,典型的就是被测服务由 docker 拉起,而 goc server 部署在另外的网络。
|
||||||
|
|
||||||
|
## 新设计选择
|
||||||
|
|
||||||
|
新设计只需要暴露 goc server 的地址,由插桩服务发起链接,然后保持长链接,在该长链接上构建 goc 自己的业务逻辑。
|
||||||
|
|
||||||
|
### 自行设计 TCP 应用层协议
|
||||||
|
|
||||||
|
go 语言做网络编程非常适合,非阻塞地处理“粘包”也不麻烦。但设计出来不管是纯二进制的、还是类似 HTTP 的,都不会是通用协议,后续维护和扩展估计是个大坑。
|
||||||
|
|
||||||
|
### websocket + jsonrpc2
|
||||||
|
|
||||||
|
websocket + jsonrpc2 有流式调用,消息边界。非常适合
|
||||||
|
|
||||||
|
我找到 `github.com/goriila/websocket` 和 `github.com/sourcegraph/jsonrpc2` 库,后者 import 了前者,前者没有 import 任何其它外部库,全是标准库。把两个库的代码合并一下:`github.com/lyyyuna/jsonrpc2` 就是一个无任何外部库引用的 jsonrpc 实现。
|
||||||
|
|
||||||
|
这非常适合由插桩代码来使用,因为该库没有再引用其它库,**不会污染原服务的依赖关系**。
|
||||||
|
|
||||||
|
### gRPC
|
||||||
|
|
||||||
|
老实说 gRPC 在这里更适合作为通信协议来使用,更快更通用,流式调用也有,上一小节的 `github.com/sourcegraph/jsonrpc2` 使用广度就很低。
|
||||||
|
|
||||||
|
但 gRPC 的 go 实现有一个很大的缺点,用了一些非标准库,且有版本依赖。我们不清楚原服务是不是有特定 gRPC 要求,或是 goc 插入的 gRPC 库会导致编译依赖冲突,或者是编译后运行冲突。
|
||||||
|
|
||||||
|
所以不适合。
|
||||||
|
|
||||||
|
### 结论
|
||||||
|
|
||||||
|
先使用 websocket + jsonrpc2 来做吧。
|
||||||
|
|
||||||
|
## 协议内容
|
||||||
|
|
||||||
|
### 注册
|
||||||
|
|
||||||
|
### 获取覆盖率
|
||||||
|
|
||||||
|
### 清空覆盖率
|
||||||
|
|
||||||
|
### watch
|
||||||
|
|
||||||
|
### 异常处理
|
@ -1,2 +1,12 @@
|
|||||||
# 返回 error 还是原地 fatal
|
# 返回 error 还是原地 fatal
|
||||||
|
|
||||||
|
哪种好呢?在一个纯命令行应用中,及时 fatal,并能在 Panic 中打印出堆栈对调试即为有意。
|
||||||
|
|
||||||
|
若是返回 error,虽然看起来:
|
||||||
|
|
||||||
|
1. 对每种异常处理都定义的很清楚(有明确的错误消息)
|
||||||
|
2. 写单测也更容易
|
||||||
|
|
||||||
|
但是 Go 的错误处理,导致 error 被一层层返回,以至于在最上层拿到 error 时你都分不清有几层了 -_-,虽然 Go 1.13 的 error wrap 一定程度消减了这个问题,但还是不如 Panic 来的好调试。
|
||||||
|
|
||||||
|
而且 goc 并不是一个供大家使用的库,目前来看 fatal 还是更适合。
|
@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2020 Qiniu Cloud (qiniu.com)
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package websocket
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Dialer contains all options for connecting to a specified websocket server
|
|
||||||
type Dialer struct {
|
|
||||||
Proxy func(*http.Request) (*url.URL, error)
|
|
||||||
HandshakeTimeout time.Duration
|
|
||||||
Subprotocols []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultDialer is dialer with all necessary fields set to default value
|
|
||||||
var DefaultDialer = &Dialer{
|
|
||||||
Proxy: http.ProxyFromEnvironment,
|
|
||||||
HandshakeTimeout: 45 * time.Second,
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Dialer) Dial() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Dialer) DialContext(ctx context.Context) {
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user