go-gin 请求取消

问题描述 投票:0回答:2

如果连接在 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()
}
go httprequest go-gin go-context
2个回答
9
投票

您可以异步运行长时间运行的操作,并将其发送到通道以表示完成。

然后你用

c.Request.Context().Done()
语句阻止该完成通道和
select

func main() {
    r := gin.Default()
    r.GET("/ping", func(c *gin.Context) {
        signal := make(chan struct{}, 1)

        go longRunningOperation(signal)

        select {
            case <-signal:
                close(signal) // remember to clean up after yourself
                // move on, will print "Processing"
    
            case <-c.Request.Context().Done():
                // abort
                return
        }

        log.Print("Processing")
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })
    r.Run()
}


func longRunningOperation(signal chan<- struct{}) {
    time.Sleep(10 * time.Second)
    signal <- struct{}{} // signal that this operation has finished
}

这种方法的缺点是,照原样,长时间运行的操作本身会继续执行。

当程序的

main

 函数返回时,
Goroutines 就会退出,而实际的
gin
服务器中并非如此。所以这可能不是你想要的。

在数据库操作的情况下,大多数API都需要一个

context.Context
参数,该参数可用于检测请求取消。因此,您可以将
c.Request.Context()
沿着调用链传递,以确保异步长时间运行的操作在客户端断开连接时也会终止。

func Handler(c *gin.Context) {
    signal := make(chan struct{}, 1)
    go longRunningOperation(c.Request.Context(), signal)
    ...
}

func longRunningOperation(ctx context.Context, signal chan<- struct{}) {
    if err := doSomethingContext(ctx); err != nil {
        return
    }
    signal <- struct{}{} // signal that this operation has finished (successfully)
}

0
投票

这种方法的问题是,尽管请求被取消,doSomethingContext 仍然会被执行。

如果您在该函数中放置打印,即使上下文被取消,您也会在终端中看到它。

这比根本没有超时更糟糕,因为当请求被取消时,应用程序回复用户说它什么也没做,但实际上它一直在执行

但我也不知道这个问题的解决方案...

© www.soinside.com 2019 - 2024. All rights reserved.