Когда я добавляю функцию отсрочки в функцию, я ожидаю, что она всегда будет вызываться после завершения функции.
Я заметил, что это не происходит, когда функция отключена.
package main
import (
"context"
"fmt"
"time"
)
func service1(ctx context.Context, r *Registry) {
ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
defer func() {
r.Unset("service 1")
}()
r.Set("service 1")
go service2(ctx, r)
select {
case <-ctx.Done():
cancel()
break
}
}
func service2(ctx context.Context, r *Registry) {
defer func() {
r.Unset("service 2")
}()
r.Set("service 2")
time.Sleep(time.Millisecond * 300)
}
type Registry struct {
entries map[string]bool
}
func (r *Registry)Set(key string) {
r.entries[key] = true
}
func (r *Registry)Unset(key string) {
r.entries[key] = false
}
func (r *Registry)Print() {
for key, val := range r.entries {
fmt.Printf("%s -> %v\n", key, val)
}
}
func NewRegistry() *Registry {
r := Registry{}
r.entries = make(map[string]bool)
return &r
}
func main() {
r := NewRegistry()
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*200)
go service1(ctx, r)
// go service3(ctx, r)
select {
case <-ctx.Done():
fmt.Printf("context err: %s\n", ctx.Err())
cancel()
}
r.Print()
}
В приведенном выше примере, отсрочка в service2()
никогда не вызывается, и поэтому вывод:
service 1 -> false
service 2 -> true
вместо
service 1 -> false
service 2 -> false
Я понимаю, что тайм-аут означает "прекратить выполнение", но разумно выполнить отложенный код. Я не смог найти объяснения этому поведению.
И вторая часть вопроса - как изменить сервис или Registry
, чтобы быть устойчивым к таким ситуациям?