diff --git a/.golangci.yml b/.golangci.yml index ad88e4e2..b9dda458 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -112,6 +112,10 @@ issues: - gochecknoglobals source: "(nil)" + - linters: + - gochecknoglobals + source: "Default" + - linters: - gocritic source: "// output:" diff --git a/cmd/forwarder/httpbin/httpbin.go b/cmd/forwarder/httpbin/httpbin.go index da51b067..7df5ab3e 100644 --- a/cmd/forwarder/httpbin/httpbin.go +++ b/cmd/forwarder/httpbin/httpbin.go @@ -37,7 +37,7 @@ func (c *command) RunE(cmd *cobra.Command, args []string) error { return err } - return runctx.Funcs{s.Run, a.Run}.Run() + return runctx.NewGroup(s.Run, a.Run).Run() } func Command() (cmd *cobra.Command) { diff --git a/cmd/forwarder/pac/server/server.go b/cmd/forwarder/pac/server/server.go index 910fb00a..b2df7dc3 100644 --- a/cmd/forwarder/pac/server/server.go +++ b/cmd/forwarder/pac/server/server.go @@ -51,7 +51,7 @@ func (c *command) RunE(cmd *cobra.Command, args []string) error { return err } - return runctx.Run(s.Run) + return runctx.NewGroup(s.Run).Run() } func validatePACScript(script string) error { diff --git a/cmd/forwarder/run/run.go b/cmd/forwarder/run/run.go index 2780882d..fec48235 100644 --- a/cmd/forwarder/run/run.go +++ b/cmd/forwarder/run/run.go @@ -105,12 +105,12 @@ func (c *command) RunE(cmd *cobra.Command, args []string) error { c.httpProxyConfig.ResponseModifiers = append(c.httpProxyConfig.ResponseModifiers, header.Headers(c.responseHeaders)) } - var f runctx.Funcs + var g runctx.Group p, err := forwarder.NewHTTPProxy(c.httpProxyConfig, pr, cm, rt, logger.Named("proxy")) if err != nil { return err } - f = append(f, p.Run) + g.Add(p.Run) if c.apiServerConfig.Addr != "" { h := forwarder.NewAPIHandler(c.promReg, p.Ready, config, script) @@ -118,7 +118,7 @@ func (c *command) RunE(cmd *cobra.Command, args []string) error { if err != nil { return err } - f = append(f, a.Run) + g.Add(a.Run) } if c.goleak { @@ -129,7 +129,7 @@ func (c *command) RunE(cmd *cobra.Command, args []string) error { }() } - return f.Run() + return g.Run() } func Command() (cmd *cobra.Command) { diff --git a/runctx/runctx.go b/runctx/runctx.go index ad19e50a..1c8f2e24 100644 --- a/runctx/runctx.go +++ b/runctx/runctx.go @@ -15,18 +15,43 @@ import ( "golang.org/x/sync/errgroup" ) -// NotifySignals specifies signals that would cause the context to be canceled. -var NotifySignals = []os.Signal{syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT} //nolint:gochecknoglobals // This is only useful in main packages. +// DefaultNotifySignals specifies signals that would cause the context to be canceled. +var DefaultNotifySignals = []os.Signal{ + syscall.SIGINT, + syscall.SIGTERM, + syscall.SIGQUIT, +} -// Funcs is a list of functions that can be executed in parallel. -type Funcs []func(ctx context.Context) error +// Group is a collection of functions that would be run concurrently. +// The context passed to each function is canceled when any of the signals in NotifySignals is received. +type Group struct { + NotifySignals []os.Signal + funcs []func(ctx context.Context) error +} -// Run executes all funcs in parallel, and returns the first error. -// Function context is canceled when the process receives a signal from NotifySignals. -func (f Funcs) Run() error { - ctx := context.Background() - ctx, unregisterSignals := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM) - eg, ctx := errgroup.WithContext(ctx) +func NewGroup(fn ...func(ctx context.Context) error) *Group { + return &Group{ + funcs: fn, + } +} + +func (g *Group) Add(fn func(ctx context.Context) error) { + g.funcs = append(g.funcs, fn) +} + +func (g *Group) Run() error { + return g.RunContext(context.Background()) +} + +func (g *Group) RunContext(ctx context.Context) error { + sigs := g.NotifySignals + if len(sigs) == 0 { + sigs = DefaultNotifySignals + } + ctx, unregisterSignals := signal.NotifyContext(ctx, sigs...) + + var eg *errgroup.Group + eg, ctx = errgroup.WithContext(ctx) eg.Go(func() error { <-ctx.Done() @@ -34,14 +59,10 @@ func (f Funcs) Run() error { return nil }) - for _, fn := range f { + for _, fn := range g.funcs { fn := fn eg.Go(func() error { return fn(ctx) }) } return eg.Wait() } - -func Run(fn func(ctx context.Context) error) error { - return Funcs{fn}.Run() -}