杜松子酒要求取消

时间:2020-07-05 11:38:27

标签: go go-gin

如果在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()
}

1 个答案:

答案 0 :(得分:2)

您可以异步运行长时间运行的操作,并使其在通道上发送以指示完成。

然后您在该完成频道和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函数返回时,goroutine退出,而实际的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)
}
相关问题