使用"上下文"实现超时



假设我有一个函数向API端点发送web请求,我想向客户端添加一个超时,这样,如果调用花费的时间太长,则操作会因返回错误或使当前线程死机而中断。

另一个假设是,客户端功能(发送web请求的功能(来自库,并且以同步方式实现。

让我们来看看客户端函数的签名:

func Send(params map[string]string) (*http.Response, error)

我想围绕这个函数编写一个包装器,以添加超时机制。要做到这一点,我可以做到:

func SendWithTimeout(ctx context.Context, params map[string]string) (*http.Response, error) {
completed := make(chan bool)
go func() {
res, err := Send(params)
_ = res
_ = err
completed <- true
}()
for {
select {
case <-ctx.Done():
{
return nil, errors.New("Cancelled")
}
case <-completed:
{
return nil, nil // just to test how this method works
}
}
}
}

现在,当我调用新函数并传递一个可取消的上下文时,我成功地得到了一个取消错误,但运行原始Send函数的goroutine一直运行到最后。

由于该函数进行API调用,这意味着建立套接字/TCP连接实际上是在后台进行的,因此将长时间运行的API留在后台不是一个好的做法。

context.Done()被击中时,有什么标准的方法可以中断原来的Send功能吗?

这是一个"差";为先前不支持上下文支持的现有API/实现添加上下文支持的设计选择。上下文支持应该添加到使用它/监视它的现有Send()实现中,将它重命名为SendWithTimeout(),并提供一个新的Send()函数,该函数不使用上下文,并使用context.TODO()context.Background()调用SendWithTimeout()

例如,如果Send()函数进行传出HTTP调用,则可以通过使用http.NewRequest()Client.Do()来实现。在新的上下文感知版本中,使用http.NewRequestWithContext()

如果你有一个无法更改的Send()函数,那么你就是";运气不好";。函数本身必须支持上下文或取消。你不能从外面中止它。

参见相关内容:

如果上下文被取消,则终止功能执行

有可能取消未完成的郊游吗?

在Golang 中使用上下文超时停止运行功能

取消Go 中的阻塞操作

最新更新