Время ожидания Goroutine
type Response struct {
data interface{}
status bool
}
func Find() (interface{}, bool) {
ch := make(chan Response, 1)
go func() {
data, status := findCicCode()
ch <- Response{data: data, status: status}
}()
select {
case response := <-ch:
return response.data, response.status
case <-time.After(50 * time.Millisecond):
return "Request timed out", false
}
}
Итак, у меня есть вышеуказанная функция. В принципе findCicCode()
вызов функции делает 3 http-вызова внутренне внешним службам. Я добавил комбинированное время ожидания для этих трех вызовов HTTP. Не могу указать индивидуальное время ожидания в моем случае. Но он все еще делает вызовы API в фоновом режиме, если он превышает время ожидания.
Я не уверен, что здесь есть утечка горутина. Есть ли способ отменить эти запросы https, если есть тайм-аут?
2 ответа
Вы контролируете отмену http запросов с помощью context.Context
,
// create a timeout or cancelation context to suit your requirements
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
req, err := http.NewRequest("GET", location, nil)
// add the context to each request and they will be canceled in unison
resp, err := http.Do(req.WithContext(ctx))
Если вы хотите, вы можете создать свою собственную систему тайм-аута для произвольной работы, выполнив одну операцию приема на канале (в основной процедуре), и в зависимости от того, какая другая программа достигнет своей операции отправки первой - time.Sleep
или тот, кто делает реальную работу - побеждает.
Вот полный работающий пример / симуляция. Настройте значения времени ожидания и задержки для имитации различных сценариев. Канал не буферизируется и закрывается после считывания одного значения, чтобы позволить другой программе завершиться при отправке.
package main
import(
"fmt"
"time"
)
type Response struct {
Data []byte
Status int
}
func Wait(s int) {
time.Sleep(time.Duration(s) * time.Second)
}
func FindWrapper(ch chan Response, delay int) {
// Put real find stuff here...
// Dummy response after wait for testing purposes
Wait(delay)
ch <- Response{[]byte("Some data..."), 200}
}
func main() {
timeout := 3
delay := 4
ch := make(chan Response)
// whoever sends to ch first wins...
go func() {
Wait(timeout)
ch <- Response{}
}()
go FindWrapper(ch, delay)
r := <-ch
close(ch)
if r.Data == nil {
r.Status = 500 // or whatever you want for timeout status
}
fmt.Printf("Data: %s Status: %d\n", string(r.Data), r.Status)
}
Буферный канал тоже будет работать. И вы могли бы сделать то же самое с sync.WaitGroup
когда вы вызываете Add только один раз, а затем закрываете канал после wg.Wait()
,
Тем не менее, я предлагаю попробовать решение JimB использования Context
время ожидания, так как оно, вероятно, работает для вашего варианта использования и является менее сложным решением.