# #go #asynchronous #timeout #polling
Вопрос:
У меня есть служба, которая развертывается асинхронно, и мне нужно подождать определенное количество времени, пока она подключится к сети. Если по истечении указанного времени мы все еще не можем найти службу, то мы выдаем ошибку. Каков наиболее оптимальный способ записи этого в 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
, особенно если это длительный период, поскольку он не прерывается. Почему это имеет значение? Если он находится в подпрограмме и эта задача не будет завершена (т. Е. Контекст был отменен), тогда вы предпочли бы прервать ее немедленно.
Итак, чтобы создать опрос-подождите с отменой:
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):
}
}
}