Skip to content

Commit

Permalink
Better signals api
Browse files Browse the repository at this point in the history
  • Loading branch information
cristaloleg committed Oct 26, 2022
1 parent adb3f88 commit 680d16f
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 8 deletions.
38 changes: 38 additions & 0 deletions GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,41 @@ func run(ctx context.Context, args []string) error {
return nil
}
```

## Manually trigger garbage collection

Might be useful when something bad happened and you don't want to restart the binary/instance/container/etc.

```go
func triggerGC(ctx context.Context) {
appx.DoOnSignal(ctx, os.SIGUSR1, func(ctx context.Context) {
runtime.GC()
})
}
```

## Reload config on SIGHUP

Very popular pattern to add zero-restart configs to your application.

```go
type Config struct{
// some fields
}

func rereadConfig(ctx context.Context) (*Config, error) {
var cfg Config
var err error

appx.DoOnSignal(ctx, os.SIGHUP, func(ctx context.Context) {
err = json.Unmarshal(&cfg)
if err != nil{
println("oh, error :(")
}
})

return &cfg, err
}
```

Took from archived [cristalhq/sigreload](https://github.com/cristalhq/sigreload)
20 changes: 12 additions & 8 deletions appx.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"os"
"os/signal"
"runtime"
"syscall"
"time"
)
Expand All @@ -22,21 +21,26 @@ func Uptime() time.Duration {
return time.Since(startTime)
}

// DoGCWhen one of the given signal happens (GC means runtime.GC()).
// DoOnSignal runs fn on every signal.
// Function is async, context is used to close underlying goroutine.
// In most cases appx.DoGCWhen(os.SIGUSR1) should be enough.
func DoGCWhen(ctx context.Context, signals ...os.Signal) {
ch := make(chan os.Signal, 1)
signal.Notify(ch, signals...)
func DoOnSignal(ctx context.Context, signal os.Signal, fn func(ctx context.Context)) {
ch := newChan(signal)

go func() {
for {
select {
case <-ch:
fn(ctx)
case <-ctx.Done():
return
case <-ch:
runtime.GC()
}
}
}()
}

// newChan returns a channel triggered on every sig.
func newChan(sig os.Signal) <-chan os.Signal {
ch := make(chan os.Signal, 1)
signal.Notify(ch, sig)
return ch
}

0 comments on commit 680d16f

Please sign in to comment.