Skip to content

Commit

Permalink
Merge pull request #179 from guoming0000/main
Browse files Browse the repository at this point in the history
add reboot for utils
  • Loading branch information
luduoxin authored Oct 23, 2024
2 parents 533e258 + 74bd739 commit ca5a9b2
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 0 deletions.
37 changes: 37 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -646,3 +646,40 @@ viper.NewConfig("config", "conf")
fmt.Println("port : ", viper.C.Get("system.port"))
fmt.Println("ENV RUN_TIME : ", viper.GetEnvConfig("run.time"))
```

### Reboot

A utility that automatically restarts the function when it crashes

```go

package main

import (
"context"

"github.com/sunmi-OS/gocore/v2/utils/closes"
)


func main() {
ctx, canel := context.WithCancel(context.Background())

// add into closes
closes.AddShutdown(closes.ModuleClose{
Name: "startAutoUpdate",
Priority: closes.MQPriority,
Func: func() {
cancel()
},
})

go reboot.AutoRestart(ctx, func() error {
// do something, will never crash
return nil
}

// wait for the program to exit
}

```
72 changes: 72 additions & 0 deletions utils/reboot/reboot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package reboot

//package main

import (
"context"
"errors"
"fmt"
"os"
"runtime"
"time"

"github.com/sunmi-OS/gocore/v2/glog"
"golang.org/x/sync/errgroup"
)


func AutoRestart(ctx context.Context, f func() error) error {
defer func() {
var r any
if r = recover(); r != nil {
buf := make([]byte, 64*1024)
buf = buf[:runtime.Stack(buf, false)]
fmt.Fprintf(os.Stderr, "reboot: panic recovered: %s\n%s\n", r, buf)
glog.Error("panic in reboot proc, err: %s, stack: %s", r, buf)

AutoRestart(ctx, f) // panic, restart
}
}()

for {
select {
case <-ctx.Done():
glog.InfoC(ctx, "reboot AutoRestart ctx done")
return ctx.Err()
default:
err := f()
if errors.Is(err, context.Canceled) {
return nil
}
// 如果返回异常,先休息会
if err != nil {
time.Sleep(time.Second * 3)
}
}
}
return nil
}


func AsyncFunc(g *errgroup.Group, f func() error) error {
defer func() {
var r any
if r = recover(); r != nil {
buf := make([]byte, 64*1024)
buf = buf[:runtime.Stack(buf, false)]
fmt.Fprintf(os.Stderr, "reboot: panic recovered: %s\n%s\n", r, buf)
glog.FatalF("panic in reboot proc, err: %s, stack: %s", r, buf)

restartAsyncLoop(g, f) // panic, restart
}
}()

return f()
}

func restartAsyncLoop(g *errgroup.Group, f func() error) {
f2 := func() error {
return AsyncFunc(g, f)
}
g.Go(f2)
}
54 changes: 54 additions & 0 deletions utils/reboot/reboot_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package reboot

import (
"context"
"fmt"
"testing"
"time"

"github.com/sunmi-OS/gocore/v2/glog"
"golang.org/x/sync/errgroup"
)

func startBooter(g *errgroup.Group, f func() error) {

f2 := func() error {
return AsyncFunc(g, f)
}
g.Go(f2)
}

func TestBootWithErrgroup(t *testing.T) {
var g errgroup.Group

startBooter(&g, bizFunc)

if err := g.Wait(); err != nil {
fmt.Println("err:", err)
}

time.Sleep(20 * time.Second)

}

func bizFunc() error {
// manual make panic for test
for i := 0; i < 10; i++ {
glog.InfoF("running in goroutine:%d", i)
time.Sleep(1 * time.Second)
if i == 5 {
panic("just boom")
}
}
return nil
}

// use method
func TestBootAutoRestart(t *testing.T) {
ctx, canel := context.WithCancel(context.Background())
go AutoRestart(ctx, bizFunc)

time.Sleep(20 * time.Second)
canel()
time.Sleep(20 * time.Second)
}

0 comments on commit ca5a9b2

Please sign in to comment.