golang的Gin框架Pool缓存池异步Context异常BUG

1 篇文章 0 订阅
1 篇文章 0 订阅

引言

前两天做的数据导入功能,考虑到后端处理比较慢,所以前端上传完文件,后端开启协程异步进行处理,同时立即返回给前端一个上传成功标识及本次上传的uuid。前端拿着返回的uuid进行轮训查询后端处理状态。逻辑上没有问题,但偶现获取 ctx 中存储的信息为空。

简化后代码如下:

package main

import (
 "fmt"
 "github.com/gin-gonic/gin"
 "time"
)

func main() {
 r := gin.Default()

 // 上传接口
 r.GET("/upload", func(c *gin.Context) {
  // 设置tid的值
  c.Set("tid", "abc")
  // 异步处理业务
  go func() {
   // 打印 ctx 的地址,以及tid的值
   fmt.Printf("\nupload-1------:%p, tid:%+v\n", c, c.Value("tid"))
   // 处理业务,使用sleep替代处理逻辑
   time.Sleep(time.Second * 10)
   // 再次打印 ctx 的地址,以及tid的值
   fmt.Printf("\nupload-2======:%p, tid:%+v\n", c, c.Value("tid"))
  }()
  // 立即返回给前端
  c.JSON(200, gin.H{
   "message": "upload pong",
   "uuid":    "123",
  })
 })

 // 获取上传后的处理状态
 r.GET("/check-status", func(c *gin.Context) {
  fmt.Printf("\ncheck-status ctx***********:%p\n", c)
  c.JSON(200, gin.H{
   "message": "check status pong",
   "uuid":    c.Query("uuid"),
  })
 })

 // 启动http服务
 if err := r.Run(":80"); err != nil {
  fmt.Println("listen err")
 }
}

经过一顿分析,发现问题是Gin的缓冲池,引起的。想要查看详细分析过程请搜索微信公众号:大胡几哥哥,或访问:golang的Gin框架异步Context异常

Gin使用缓冲池是为了提高性能,但我没有正确使用导致多个http请求,使用相同的ctx,而新请求会把缓冲池中的ctx存储的内容清空,所以异步中未完成的业务获取ctx中的内容就失败。解决办法就是使用 `c.copy` 复制一份ctx:

package main

import (
 "fmt"
 "github.com/gin-gonic/gin"
 "time"
)

func main() {
 r := gin.Default()

 // 上传接口
 r.GET("/upload", func(c *gin.Context) {
  // 设置tid的值
  c.Set("tid", "abc")
  ctx := c.Copy()
  // 异步处理业务
  go func() {
   // 打印 ctx 的地址,以及tid的值
   fmt.Printf("\nupload-1------:%p, tid:%+v\n", ctx, ctx.Value("tid"))
   // 处理业务,使用sleep替代处理逻辑
   time.Sleep(time.Second * 10)
   // 再次打印 ctx 的地址,以及tid的值
   fmt.Printf("\nupload-2======:%p, tid:%+v\n", ctx, ctx.Value("tid"))
  }()
  // 立即返回给前端
  c.JSON(200, gin.H{
   "message": "upload pong",
   "uuid":    "123",
  })
 })

 // 获取上传后的处理状态
 r.GET("/check-status", func(c *gin.Context) {
  fmt.Printf("\ncheck-status ctx***********:%p\n", c)
  c.JSON(200, gin.H{
   "message": "check status pong",
   "uuid":    c.Query("uuid"),
  })
 })

 // 启动http服务
 if err := r.Run(":80"); err != nil {
  fmt.Println("listen err")
 }
}

点击查看更多文章

更新精彩文章请关注微信公众号:大胡几哥哥

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值