我目前正在努力将我们的代码从全局符号包迁移到 mongo-driver,不确定我应该在哪里使用context.TODO()and context.Background(),它\xe2\x80\x99s 真的很令人困惑,我知道它都返回非零空,所以我应该context.Background()在主函数和init()函数中使用?还有用context.TODO()在其他地方吗?有人能帮忙吗?
尝试检查我应该使用哪个参数context.TODO()或context.Background().
如果连接在 10 秒前关闭,如何取消进一步处理?
有c.Request.Context().Done()但找不到如何使用它的示例。
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
time.Sleep(10 * time.Second) // or some db operation
log.Print("Processing")
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run()
}
Run Code Online (Sandbox Code Playgroud) 我正在尝试在令牌身份验证中间件中提取 user_id 并将其传递给gqlgen的 graphql 解析器函数(以填充 GraphQL 架构的created_by 和updated_by 列)。身份验证部分工作没有任何问题。
Gin 中间件:
var UID = "dummy"
func TokenAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
err := auth.TokenValid(c.Request)
if err != nil {
c.JSON(http.StatusUnauthorized, "You need to be authorized to access this route")
c.Abort()
return
}
//
UID, _ = auth.ExtractTokenID(c.Request)
//c.Set("user_id", UID)
c.Next()
}
}
func GetUID() string {
return UID
}
Run Code Online (Sandbox Code Playgroud)
graphql 解析器:
var ConstID = middleware.GetUID()
func (r *mutationResolver) CreateFarmer(ctx context.Context, input model.NewFarmer) (*model.Farmer, error) {
//Fetch …Run Code Online (Sandbox Code Playgroud) 感谢这里的任何帮助!我确信我错过了一些非常基本的东西。
我遇到的问题是我试图在演示 Web 应用程序中获取脱离上下文的值,并且收到错误:
2021/04/11 11:35:54 http: panic serving [::1]:60769: interface conversion: interface {} is nil, not []string
在我的主要函数中,我使用以下内容设置上下文:
package main
type ctxKey struct{}
func someHttpHandleFunc() {
// .....
ctx := context.WithValue(r.Context, ctxKey{}, matches[1:])
route.handle(w, r.WithContext(ctx))
}
Run Code Online (Sandbox Code Playgroud)
然后在我的处理程序中,我有以下内容:
package some_package
type ctxKey struct{}
func getField(r *http.Request, index int) string {
fields := r.Context().Value(ctxKey{}).([]string)
return fields[index]
}
Run Code Online (Sandbox Code Playgroud)
我知道我错过了一些简单的东西,因为如果我尝试上面的代码并将我的getField()函数放在package main一切正常的情况下。
作为参考,这是一个学习练习,我正在尝试自学 Go 路由。我确实知道有可用的路由包 - 但我的目标是学习。我正在尽力遵循Go 中 HTTP 路由的不同方法。我还阅读了上下文值的陷阱以及如何在 Go 中避免或减轻它们。后者似乎直接解决了我遇到的问题,但我似乎无法根据现有的情况找出如何解决它。
我正在使用Echo 框架,并希望在设置一些自定义值后传递 Go 内置的底层context.Context echo.Context。
为了实现它,我想我可以首先应用 的Set(key string, val interface{})方法echo.Context,然后提取底层的context.Context.
问题是可以这样做吗?换句话说,是否像echo.Context.Set(...)直接设置值一样?或者我应该采取额外的步骤来复制我的自定义条目。context.ContextWithValue
PS我不想传递echo.Context到我的应用程序的更深层次,这就是为什么我不想直接使用它但得到引用context.Context
我一直在阅读一些关于使用 golang 的 context 包的文章。我最近在博客中看到以下文章:http://p.agnihotry.com/post/understanding_the_context_package_in_golang/
这篇文章对 go 中的上下文取消函数做了以下说明:
“如果您愿意,您可以传递取消函数,但是,强烈不建议这样做。这可能会导致取消的调用者没有意识到取消上下文可能对下游产生什么影响。可能还会派生出其他上下文这可能会导致程序以意想不到的方式运行。简而言之,永远不要传递取消函数。”
但是,如果我希望激活父 context.Done() 通道,将取消函数作为参数传递似乎是唯一的选择(请参阅下面的代码片段)。例如,下面代码片段中的代码 Done 通道仅在执行 function2 时激活。
package main
import (
"context"
"fmt"
"time"
)
func function1(ctx context.Context) {
_, cancelFunction := context.WithCancel(ctx)
fmt.Println("cancel called from function1")
cancelFunction()
}
func function2(ctx context.Context, cancelFunction context.CancelFunc) {
fmt.Println("cancel called from function2")
cancelFunction()
}
func main() {
//Make a background context
ctx := context.Background()
//Derive a context with cancel
ctxWithCancel, cancelFunction := context.WithCancel(ctx)
go function1(ctxWithCancel)
time.Sleep(5 * time.Second)
go function2(ctxWithCancel, cancelFunction) …Run Code Online (Sandbox Code Playgroud) 我正在研究oklog/run包的一个简单示例,并且在尝试返回错误日志时在 VS Code 中看到此编译错误:
\nlog.Errorf("abnormal termination: %s", err) (no value) used as value\nRun Code Online (Sandbox Code Playgroud)\n在 group.Run 的描述中说
\n\n\n“..Run 仅在所有 actor 退出时返回。Run 返回第一个退出的 actor 返回的错误。”
\n
我\xe2\x80\x99m想知道这是否与它有关,比如它可以\xe2\x80\x99t编译当前不存在的错误,因为run.Group尚未全部返回?
\n感谢您提供的任何帮助。
\n代码:
\npackage main\n\nimport (\n "context"\n "time"\n\n "github.com/oklog/run"\n "github.com/pkg/errors"\n log "github.com/sirupsen/logrus"\n)\n\nfunc logAForever(ctx context.Context) {\n for {\n select {\n case err := <-ctx.Done():\n log.Error(err)\n return\n default:\n log.Info("A")\n time.Sleep(1 * time.Second)\n }\n }\n}\n\nfunc logBFor10Sec(ctx context.Context) {\n for i := 1; i < 10; i++ {\n log.Info("B")\n time.Sleep(1 …Run Code Online (Sandbox Code Playgroud) 我已经做了很多关于上下文的研究,但我似乎找不到普遍接受的答案,而且我是Go的新手。
在我当前的代码中,我var ctx = context.Background()已经在各个地方使用了它。
我担心的是,我的所有代码不是都修改相同的上下文吗,因为它是全局变量?。
是的,我知道上下文是请求范围的。
这是我的上下文代码的一部分。
var ctx = context.Background()
var db *firestore.Client
var auth *aut.Client
func init() {
app, err := firebase.NewApp(ctx, nil)
if err != nil {
log.Fatal(err)
}
db, err = app.Firestore(ctx)
if err != nil {
log.Fatal(err)
}
auth, err = app.Auth(ctx)
if err != nil {
log.Fatal(err)
}
}
func SetRate(r int) (err error) {
//TODO: create last updated field
_, err = db.Collection("Rate").Doc("rate").Set(ctx, map[string]int{"USDT": r})
if …Run Code Online (Sandbox Code Playgroud) 我在这里使用半代码只是为了表明我对代码中发生的事情的意图,而不是使问题中的事情复杂化。
我有一个main.go文件调用连接到 mongoDB 数据库的方法:
mStore := store.NewMongoStore()
Run Code Online (Sandbox Code Playgroud)
在我有用于连接数据库的NewMongoStore上下文中:client.Connect
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
Run Code Online (Sandbox Code Playgroud)
现在,main.go我通过这种方式将商店传递给我的路由器控制器文件:
routes.GenericRoute(router, mStore)
Run Code Online (Sandbox Code Playgroud)
在GenericRoute我获取 mStore 并将其传递给函数处理程序:
func GenericRoute(router *gin.Engine, mStore store.Store) {
router.POST("/users", controllers.CreateUser(mStore))
}
Run Code Online (Sandbox Code Playgroud)
现在,CreateUser我再次创建一个上下文,如下所示,将文档插入到 MongoDB 中:
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
insertedId, err := repo.CreateUser(ctx, newUser{"John", "Doe"})
Run Code Online (Sandbox Code Playgroud)
在这里,我传递了上下文来createUser插入新文档。
正如你所看到的,在某些部分我已经传递了上下文,而在某些部分我没有。我真的不知道我应该做什么?处理上下文的正确方法是什么?我是否应该始终传递上下文,或者创建像这样的新上下文而不在方法参数中传递上下文是完全可以的。
这种编码的最佳实践是什么?从性能角度来看,哪一个更好?
尝试了解 go 上下文取消如何中止后续代码的执行
实验详情:
2secsum在单独的 go-routine 中调用另一个 func - 它为1sectest-run-1 和4sectest-run-2休眠3sec让 spin go 例程完成执行package main
import (
"context"
"fmt"
"log"
"time"
)
func main() {
c := context.Background()
childCtx, cancel := context.WithTimeout(c, 2*time.Second)
defer cancel()
ch := make(chan int, 1)
go sum(5, 6, ch)
var msg string
select {
case <-childCtx.Done():
msg = "return from ctx done channel"
case res := <-ch:
msg = …Run Code Online (Sandbox Code Playgroud) 考虑一下(https://play.golang.org/p/zvDiwul9QR0):
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
for {
select {
case <-ctx.Done():
fmt.Println("Done")
break
default:
for {
fmt.Println("loop")
time.Sleep(500 * time.Millisecond)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以这里上下文在 2 秒后返回一个“Done()”通道。我想抓住这个并取消我的无限循环。上面的代码示例没有这样做,它永远不会退出循环。
我怎样才能实现这个目标?
当我通过 golang\xef\xbc\x8c 创建上下文 WithCancel 函数时为什么建议在函数末尾运行 cancelFunc\xe3\x80\x82\n我认为 \xef\xbc\x8cassume 我使用 gin 框架,当前函数运行后完成\xef\xbc\x8c gin的上下文会破坏\xe3\x80\x82所以是否有必要在\ndefine之后运行cancelFunc context.WithCancel(ctx),defer cancelFunc()
func myFunction(ctx *context.Context) error {\n cancelCtx, cancelFunc := context2.WithCancel(ctx)\n defer cancelFunc()\n\n var (\n successTask = int32(0)\n failTask = int32(0)\n wg = &sync.WaitGroup{}\n )\n\n select {\n case <-cancelCtx.Done():\n break\n default:\n for i := 0; i < 100; i++{\n wg.add(1)\n\n go func(){\n defer wg.Done()\n\n err := myLogic()\n if err != nil {\n atomic.AddInt32(&failTask, 1)\n cancelFunc()\n return\n }\n atomic.AddInt32(&successTask, 1)\n }\n }\n \n \n }\n\n wg.Wait()\n return …Run Code Online (Sandbox Code Playgroud) go ×12
go-context ×12
go-gin ×3
httprequest ×2
go-echo ×1
goroutine ×1
gqlgen ×1
graphql ×1
httprouter ×1
mongodb ×1