Skip to content

Commit

Permalink
runctx: refactoring
Browse files Browse the repository at this point in the history
- NotifySignals is renamed to DefaultNotifySignals
- Hard coded signals are removed
- New struct Group provides better DSL
- Duplicated code is removed
  • Loading branch information
mmatczuk committed Jun 5, 2023
1 parent b3e7c66 commit edb6251
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 21 deletions.
4 changes: 4 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ issues:
- gochecknoglobals
source: "(nil)"

- linters:
- gochecknoglobals
source: "Default"

- linters:
- gocritic
source: "// output:"
Expand Down
2 changes: 1 addition & 1 deletion cmd/forwarder/httpbin/httpbin.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion cmd/forwarder/pac/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
8 changes: 4 additions & 4 deletions cmd/forwarder/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,20 +105,20 @@ 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)
a, err := forwarder.NewHTTPServer(c.apiServerConfig, h, logger.Named("api"))
if err != nil {
return err
}
f = append(f, a.Run)
g.Add(a.Run)
}

if c.goleak {
Expand All @@ -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) {
Expand Down
51 changes: 36 additions & 15 deletions runctx/runctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,54 @@ 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()
unregisterSignals()
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()
}

0 comments on commit edb6251

Please sign in to comment.