kamilsk / retry

♻️ The most advanced interruptible mechanism to perform actions repetitively until successful.
https://pkg.go.dev/github.com/kamilsk/retry/v5
MIT License
340 stars 14 forks source link

wat moment: Schrödinger's bug #171

Closed kamilsk closed 3 years ago

kamilsk commented 3 years ago

I ran into an unpleasant problem:

ctx = // some top-level context

client = // some http client
req := http.NewRequestWithContext(...)

var resp *http.Response

action := func(ctx context.Context) error {
    var err error
    resp, err = client.Do(req.WithContext(ctx)) // it's important to wrap action's ctx to try to reproduce the problem
    return err
}

if err := retry.Do(ctx, action, ...); err != nil {
    return nil, err
}
defer safe.Close(io.Discarded(resp.Body), unsafe.Ignore)

var result map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
    return nil, err
}
return result, nil // it's fluky because I also may have a "context canceled" error

It's happening because I cancel the action's context on success https://github.com/kamilsk/retry/blob/13994452f848aa8b4f15f17cb82c55703f465b1b/retry.go#L69 and https://github.com/golang/go/blob/0f66fb7b856b02497cf801ce72d80f375f53358b/src/net/http/client.go#L928-L960

I can't don't do it cause of goroutine leaking

What I have to do: