Если вы хотите использовать функцию тайм-аут и отмену из контекста, то ctx.Done()
необходимо обрабатывать синхронно.
Пояснение от https://golang.org/pkg/context/#Context
Done возвращает канал, который закрыт, когда работа, выполненная от имени этого контекста, должна быть отменена.Готово может вернуть ноль, если этот контекст никогда не может быть отменен.Последовательные вызовы Done возвращают одно и то же значение.
Таким образом, в основном <-ctx.Done()
будет вызываться при двух условиях:
- , когда время ожидания контекста превышает
- когда контекст отменяется силой
И когда это происходит, ctx.Err()
никогда не будет nil
.Затем мы можем выполнить некоторую проверку объекта ошибки, чтобы увидеть, был ли контекст отменен принудительно или превысил время ожидания.
Пакет контекста предоставляет объект двух ошибок, context.DeadlineExceeded
и context.Timeout
, эти два помогут намлегко понять, почему выполняется <-ctx.Done()
.
Пример использования сценария: превышено время ожидания контекста
В тесте мы попытаемся отменить контекст до истечения времени ожидания, поэтому <-ctx.Done()
будет выполнено.
ctx, cancel := context.WithTimeout(
context.Background(),
time.Duration(3*time.Second))
defer cancel()
go func(ctx context.Context) {
defer cancel()
// simulate a process that takes 2 second to complete
time.Sleep(2 * time.Second)
}(ctx)
select {
case <-ctx.Done():
switch ctx.Err() {
case context.DeadlineExceeded:
fmt.Println("context timeout exceeded")
case context.Canceled:
fmt.Println("cancel the context by force")
}
}
Вывод:
$ go run test.go
cancel the context by force
Пример использования сценария: превышено время ожидания контекста
В этом сценариимы делаем процесс дольше, чем время ожидания контекста, поэтому в идеале <-ctx.Done()
также будет выполняться.
ctx, cancel := context.WithTimeout(
context.Background(),
time.Duration(3*time.Second))
defer cancel()
go func(ctx context.Context) {
defer cancel()
// simulate a process that takes 4 second to complete
time.Sleep(4 * time.Second)
}(ctx)
select {
case <-ctx.Done():
switch ctx.Err() {
case context.DeadlineExceeded:
fmt.Println("context timeout exceeded")
case context.Canceled:
fmt.Println("cancel the context by force")
}
}
Вывод:
$ go run test.go
context timeout exceeded