我想问一下,我们应该如何在Golang处理上下文传播的问题。
我的应用程序是HTTP服务器。
我会使用上下文作为信息数据的容器(例如请求id,我从请求或进程中解压缩的一些东西)。
其中最愚蠢的优点之一是车辆数据和标签有用的统计和日志记录。例如,能够在每一行日志中添加我所拥有的所有包中的事务id。
我面临的问题如下:
func handleActivityY(w http.ResponseWriter, r *http.Request) {
info, err := decodeRequest(r)
...
stepOne, err := stepOne(r.Context(), info)
...
stepTwo, err := stepTwo(r.Context(), stepOne)
...
}这个设计的问题在于,上下文是一个不可变的实体(每当我们添加某个内容或设置一个新的超时时,我们就会有一个新的上下文)。
除非在每个函数调用时返回上下文(以及返回值(如果有的话)和错误),否则不能传播上下文。
要使这项工作发挥作用,唯一的办法是:
func handleActivityY(w http.ResponseWriter, r *http.Request) {
ctx, info, err := decodeRequest(r)
...
ctx, stepOne, err := stepOne(ctx, info)
...
ctx, stepTwo, err := stepTwo(ctx, stepOne)
...
}我已经用context.Context参数污染了包中的几乎所有函数。在我看来,除了其他参数之外,还返回它似乎有些过火了。
难道真的没有其他更优雅的方法来做到这一点吗?
我目前正在使用gin框架,它有自己的上下文,并且是可变的。我不想为此向Gin添加依赖项。
发布于 2018-03-09 07:25:09
在上下文管道的早期,向数据结构添加一个可变指针:
type MyData struct {
// whatever you need
}
var MyDataKey = /* something */
ctx, cancel := context.WithValue(context.Background(), MyDataKey, &MyData{})然后,在需要修改数据结构的方法中,只需这样做:
data := ctx.Value(MyDataKey)
data.Foo = /* something */所有关于并发访问安全的常规规则都适用,因此,如果多个goroutines可以同时读取/设置数据值,则可能需要使用互斥或其他保护机制。
发布于 2018-03-08 19:13:23
难道真的没有其他更优雅的方法来做到这一点吗?
stepOne可以独立于上下文返回自己的数据,并与调用者如何使用其信息隔离(即将其放入数据库/上下文并将其传递给其他函数)
func handleActivityY(w http.ResponseWriter, r *http.Request) {
ctx, info, err := decodeRequest(r)
...
stepOne, err := stepOne(ctx, info)
...
ctx = context.WithValue(ctx, "someContextStepTwoNeeds", stepOne.Something())
stepTwo, err := stepTwo(ctx, stepOne)
...
}所传递的IMO数据的作用域应该是极小的上下文信息。
https://stackoverflow.com/questions/49180425
复制相似问题