contextcheck icon indicating copy to clipboard operation
contextcheck copied to clipboard

False-positive with a graceful shutdown

Open AlekSi opened this issue 4 years ago • 4 comments

Simplified example:

// Run runs server until ctx is canceled, then stops it gracefully and exits.
func RunHandler(ctx context.Context) {
	s := http.Server{
		BaseContext: func(_ net.Listener) context.Context {
			return ctx
		},
	}

	go s.ListenAndServe()
	<-ctx.Done()

	// use new context for cancelation
	stopCtx, stopCancel := context.WithTimeout(context.Background(), time.Second) 
	defer stopCancel()
	s.Shutdown(stopCtx)

	s.Close()
}

stopCtx can't be inherited from ctx as the later is already canceled.

Maybe this linter can detect that <-ctx.Done() was already called by this point?

AlekSi avatar Nov 06 '21 07:11 AlekSi

The same I faced with. It is more abstract example

package main

import (
	"context"
)

func main() {
	doSmth(context.Background())
}

func doSmth(ctx context.Context) {
	doSmth2(ctx)

	// I want to use context.Background() here
	ctx2, ctx2Cancel := context.WithCancel(context.Background())
	defer ctx2Cancel()

	doSmth2(ctx2)
}

func doSmth2(ctx context.Context) {
	_ = ctx
}
main.go:17:9: Non-inherited new context, use function like `context.WithXXX` instead (contextcheck)
        doSmth2(ctx2)

The issue occurs when context is provided into the function but I want to use another context instance intentionally. For example graceful shutdown should be done with Background context.

And currently there is no way to avoid this error from the linter

nawa avatar Dec 03 '21 17:12 nawa

this case can write func like this to pass

func NoInheritCancel(_ context.Context) (context.Context,context.CancelFunc) {
  return context.WithCancel(context.Background())
}

kkHAIKE avatar May 15 '22 02:05 kkHAIKE