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 - 实现超时的最佳方式的主要内容,如果未能解决你的问题,请参考以下文章

go 通过select实现超时

使用 select 实现 goroutine 超时

Go:分布式锁实现原理与最佳实践

go并发-异步和超时控制

go并发-异步和超时控制

go并发-异步和超时控制