diff --git a/.github/wordlist.txt b/.github/wordlist.txt index f58f64e2e..7d8a1b79b 100644 --- a/.github/wordlist.txt +++ b/.github/wordlist.txt @@ -99,9 +99,6 @@ UUID Unmarshalers XYZ YAML -- "dependending" - should be "depending" -- "logics" - should be "logic" (uncountable noun) -- "maintainance" - should be "maintenance" ad'hoc agentic allocs diff --git a/internal/leak/leak.go b/internal/leak/leak.go index 5ee4f3841..259a9315f 100644 --- a/internal/leak/leak.go +++ b/internal/leak/leak.go @@ -19,6 +19,12 @@ import ( const labelKey = "testify-leak-check" +const ( + maxAttempts = 20 + maxWait = 100 * time.Millisecond + waitFactor = 2 +) + func init() { //nolint:gochecknoinits // this init check is justify by the use of an internal volatile API. // check that the profile API behaves as expected or panic. // @@ -42,6 +48,24 @@ func init() { //nolint:gochecknoinits // this init check is justify by the use o needle := buildNeedle(id) profile := captureProfile() match := extractLabeledBlocks(profile, needle) + if match == "" { + // goroutine may not be scheduled yet: wait a bit before taking a decision + + wait := time.Microsecond + for range maxAttempts { + time.Sleep(wait) // brief retry: goroutines may be mid-exit. + profile = captureProfile() + match = extractLabeledBlocks(profile, needle) + if match != "" { + break + } + + // retry — goroutine might still be exiting + // wait exponential backoff, capped to maxWait + wait = min(wait*waitFactor, maxWait) + } + } + close(blocker) wg.Wait() if match == "" { @@ -69,16 +93,11 @@ func Leaked(ctx context.Context, tested func()) string { return "" // early exit: clean state } - const ( - maxAttempts = 20 - maxWait = 100 * time.Millisecond - waitFactor = 2 - ) wait := time.Microsecond for range maxAttempts { time.Sleep(wait) // brief retry: goroutines may be mid-exit. - profile := captureProfile() - match := extractLabeledBlocks(profile, needle) + profile = captureProfile() + match = extractLabeledBlocks(profile, needle) if match == "" { return "" // clean }