go-zero icon indicating copy to clipboard operation
go-zero copied to clipboard

How to make gracefulStop waiting?

Open fireice009 opened this issue 1 year ago β€’ 8 comments

the code is generated by goctl, and just added test() function.

func main() {
	flag.Parse()

	var c config.Config
	conf.MustLoad(*configFile, &c)

	server := rest.MustNewServer(c.RestConf)
	defer server.Stop()

	ctx := svc.NewServiceContext(c)
	handler.RegisterHandlers(server, ctx)

	test()
	fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
	server.Start()
}

func test() {
	proc.SetTimeToForceQuit(time.Minute)
	proc.AddWrapUpListener(func() {
		fmt.Println("wrap up start...")
		time.Sleep(5 * time.Second)
		fmt.Println("wrap up done")
	})

build and run it in Linux,then send SIGNTERM, it print log

root@VM-0-16-debian:~# ./demo2 -f demo2-api.yaml
Starting server at 0.0.0.0:8888...
{"@timestamp":"2024-04-21T18:38:06.608+08:00","caller":"proc/shutdown.go:58","content":"Got signal 15, shutting down...","level":"info"}
wrap up start...
{"@timestamp":"2024-04-21T18:38:07.609+08:00","caller":"stat/metrics.go:210","content":"(demo2-api) - qps: 0.0/s, drops: 0, avg time: 0.0ms, med: 0.0ms, 90th: 0.0ms, 99th: 0.0ms, 99.9th: 0.0ms","level":"stat"}

Why it does not wait the listener's func done? How to make it wait?

fireice009 avatar Apr 21 '24 10:04 fireice009

func signalHandler() {
	// signal handler
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
	for {
		s := <-c
		switch s {
		case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
			// do what you want
			return
		case syscall.SIGHUP:
		default:
			return
		}
	}
}

jaronnie avatar Apr 24 '24 06:04 jaronnie

demo repo: https://github.com/jaronnie/jzero/blob/main/daemon/daemon.go

jaronnie avatar Apr 24 '24 06:04 jaronnie

Bot detected the issue body's language is not English, translate it automatically. πŸ‘―πŸ‘­πŸ»πŸ§‘β€πŸ€β€πŸ§‘πŸ‘«πŸ§‘πŸΏβ€πŸ€β€πŸ§‘πŸ»πŸ‘©πŸΎβ€πŸ€β€πŸ‘¨πŸΏπŸ‘¬πŸΏ


But report: https://gityub. Kom/jaron-ie/jzero/bb/main/daemon/daemon. Go

Issues-translate-bot avatar Apr 24 '24 06:04 Issues-translate-bot

go-zero already has this logic, but the function 'gracefulStop' did not execute as expected.

core/proc/signals.go

func init() {
	go func() {
		// https://golang.org/pkg/os/signal/#Notify
		signals := make(chan os.Signal, 1)
		signal.Notify(signals, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGTERM, syscall.SIGINT)

		for {
			v := <-signals
			switch v {
			case syscall.SIGUSR1:
				dumpGoroutines(fileCreator{})
			case syscall.SIGUSR2:
				profiler := StartProfile()
				time.AfterFunc(profileDuration, profiler.Stop)
			case syscall.SIGTERM:
				stopOnSignal()
				gracefulStop(signals, syscall.SIGTERM)
			case syscall.SIGINT:
				stopOnSignal()
				gracefulStop(signals, syscall.SIGINT)
			default:
				logx.Error("Got unregistered signal:", v)
			}
		}
	}()
}

fireice009 avatar Apr 25 '24 05:04 fireice009

waitForCalled := proc.AddWrapUpListener(func() {
	fmt.Println("wrap up start...")
	time.Sleep(5 * time.Second)
	fmt.Println("wrap up done")
})
waitForCalled()

kevwan avatar May 06 '24 10:05 kevwan

waitForCalled := proc.AddWrapUpListener(func() {
	fmt.Println("wrap up start...")
	time.Sleep(5 * time.Second)
	fmt.Println("wrap up done")
})
waitForCalled()

waitForCalled() will block the flow, before server.Start()

fireice009 avatar May 08 '24 13:05 fireice009

waitForCalled := proc.AddWrapUpListener(func() {
	fmt.Println("wrap up start...")
	time.Sleep(5 * time.Second)
	fmt.Println("wrap up done")
})
waitForCalled()

waitForCalled() will block the flow, before server.Start()

Call it after server started.

kevwan avatar May 08 '24 13:05 kevwan

server.Start() will block the main thread. gracefulStop does not wait when i run test() in a new goroutine.

fireice009 avatar May 12 '24 03:05 fireice009