Go - 实现超时的最佳方式
Posted
技术标签:
【中文标题】Go - 实现超时的最佳方式【英文标题】:Go - The most optimal way to implement a timeout 【发布时间】:2021-12-23 12:34:50 【问题描述】:我有一个异步部署的服务,我需要等待指定的时间才能使其上线。如果指定的时间过去了,我们仍然无法找到服务,那么我们就会出错。在 go 中写这个的最佳方式是什么?我正在考虑使用context.WithTimeout
,但不确定它到底是如何工作的。感谢您的帮助!
func (c *Client) WaitForServiceToComeAlive(ctx context.Context, name string, timeout time.Duration) error
var mysvc *Service
var err error
endtime := time.Now().Add(timeout)
for time.Now().Before(endtime)
mysvc, err = c.GetService(ctx, name)
if err != nil
return err
if mysvc != nil
break
time.Sleep(time.Second * 10)
if mysvc == nil
return fmt.Errorf("svc %s did not register", name)
return nil
【问题讨论】:
【参考方案1】:永远不要使用time.Sleep
,尤其是在长时间使用的情况下 - 因为它是不间断的。为什么这很重要?如果它在一个 goroutine 中并且该任务不会完成(即上下文被取消),那么您宁愿立即中止。
所以要创建一个带有取消的轮询等待:
select
case <-ctx.Done(): // cancel early if context is canceled
return ctx.Err()
case <-time.After(pollInterval): // wait for pollInterval duration
将较大的超时设置在输入上下文中:
ctx := context.TODO() // <- outer request context goes here or context.Background()
// wrap context with a timeout
ctx, cancel := context.WithTimeout(ctx, 1 * time.Minute)
defer cancel() // avoid leaks
err := c.WaitForServiceToComeAlive(ctx, "job", 10*time.Second /* poll interval */)
然后您的服务等待函数简化为:
func (c *Client) WaitForServiceToComeAlive(ctx context.Context, name string, pollInterval time.Duration) error
var mysvc *Service
var err error
for
mysvc, err = c.GetService(name) // <- this should take a ctx too - if possible for early cancelation
if err != nil
return err
if mysvc != nil
return nil
select
case <-ctx.Done():
return ctx.Err()
case <-time.After(pollInterval):
https://play.golang.org/p/JwH5CMyY0I2
【讨论】:
以上是关于Go - 实现超时的最佳方式的主要内容,如果未能解决你的问题,请参考以下文章