Skip to content

Commit

Permalink
Merge pull request #399 from askuy/feature/gracefulstop
Browse files Browse the repository at this point in the history
graceful stop
  • Loading branch information
askuy authored Jun 18, 2024
2 parents 343b533 + 00299e7 commit 3046864
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 13 deletions.
12 changes: 10 additions & 2 deletions ego.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/gotomicro/ego/server"
"github.com/gotomicro/ego/task/ecron"
"github.com/gotomicro/ego/task/ejob"
"go.uber.org/zap"
)

// Ego 分为三大部分
Expand All @@ -43,6 +44,13 @@ type Ego struct {

// 第三部分 可选方法
opts opts

// stopStartTime
stopInfo stopInfo
}
type stopInfo struct {
stopStartTime time.Time
isGracefulStop bool
}

type opts struct {
Expand Down Expand Up @@ -232,11 +240,11 @@ func (e *Ego) Run() error {

// 阻塞,等待信号量
if err := <-e.cycle.Wait(e.opts.hang); err != nil {
e.logger.Error("Ego shutdown with error", elog.FieldComponent("app"), elog.FieldErr(err))
e.logger.Error("Ego shutdown with error", elog.FieldComponent("app"), elog.FieldErr(err), elog.FieldCost(time.Since(e.stopInfo.stopStartTime)), zap.Bool("grace", e.stopInfo.isGracefulStop), zap.String("stopTimeout", e.opts.stopTimeout.String()))
runSerialFuncLogError(e.opts.afterStopClean)
return err
}
e.logger.Info("stop Ego, bye!", elog.FieldComponent("app"))
e.logger.Info("stop ego, bye!", elog.FieldComponent("app"), elog.FieldCost(time.Since(e.stopInfo.stopStartTime)), zap.Bool("grace", e.stopInfo.isGracefulStop), zap.String("stopTimeout", e.opts.stopTimeout.String()))
// 运行停止后清理
runSerialFuncLogError(e.opts.afterStopClean)
return nil
Expand Down
15 changes: 9 additions & 6 deletions ego_function.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import (
"os/signal"
"runtime"
"syscall"
"time"

sentinelmetrics "github.com/alibaba/sentinel-golang/metrics"
"github.com/prometheus/client_golang/prometheus"
"go.uber.org/automaxprocs/maxprocs"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"

"github.com/gotomicro/ego/core/constant"
Expand Down Expand Up @@ -42,23 +42,26 @@ func (e *Ego) waitSignals() {
grace := s != syscall.SIGQUIT
go func() {
// todo 父节点传context待考虑
stopCtx, cancel := context.WithTimeout(context.Background(), e.opts.stopTimeout)
e.stopInfo = stopInfo{
stopStartTime: time.Now(),
isGracefulStop: grace,
}
stopCtx, cancel := context.WithTimeoutCause(context.Background(), e.opts.stopTimeout, fmt.Errorf("stop timeout %v", e.opts.stopTimeout))

defer func() {
signal.Stop(sig)
cancel()
}()

elog.Info("server stop", zap.Bool("graceful", grace))

_ = e.Stop(stopCtx, grace)
<-stopCtx.Done()
// 记录服务器关闭时候,由于关闭过慢,无法正常关闭,被强制cancel
if errors.Is(stopCtx.Err(), context.DeadlineExceeded) {
elog.Error("waitSignals stop context err", elog.FieldErr(stopCtx.Err()))
e.logger.Error("waitSignals stop context err", elog.FieldErr(stopCtx.Err()))
}
}()
<-sig
elog.Error("waitSignals quit")
e.logger.Error("waitSignals quit")
// 因为os.Signal长度为2,那么这里会阻塞住,如果发送两次信号量,强制退出
os.Exit(128 + int(s.(syscall.Signal))) // second signal. Exit directly.
}()
Expand Down
10 changes: 8 additions & 2 deletions server/egin/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,10 @@ func (c *Component) Stop() error {
c.mu.Lock()
err := c.Server.Close()
c.mu.Unlock()
return err
if err != nil {
return fmt.Errorf("egin Stop, err: %w", err)
}
return nil
}

// GracefulStop implements server.Component interface
Expand All @@ -190,7 +193,10 @@ func (c *Component) GracefulStop(ctx context.Context) error {
c.mu.Lock()
err := c.Server.Shutdown(ctx)
c.mu.Unlock()
return err
if err != nil {
return fmt.Errorf("egin GracefulStop, err: %w", err)
}
return nil
}

// Info returns server info, used by governor and consumer balancer
Expand Down
13 changes: 11 additions & 2 deletions server/egovernor/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package egovernor
import (
"context"
"encoding/json"
"fmt"
"net"
"net/http"
"net/http/pprof"
Expand Down Expand Up @@ -153,12 +154,20 @@ func (c *Component) Start() error {

// Stop ..
func (c *Component) Stop() error {
return c.Server.Close()
err := c.Server.Close()
if err != nil {
return fmt.Errorf("egovernor Stop, err: %w", err)
}
return nil
}

// GracefulStop ..
func (c *Component) GracefulStop(ctx context.Context) error {
return c.Server.Shutdown(ctx)
err := c.Server.Shutdown(ctx)
if err != nil {
return fmt.Errorf("egovernor GracefulStop, err: %w", err)
}
return nil
}

// Info ..
Expand Down
7 changes: 6 additions & 1 deletion server/egrpc/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package egrpc

import (
"context"
"fmt"
"net"

"github.com/gotomicro/ego/core/constant"
Expand Down Expand Up @@ -157,7 +158,11 @@ func (c *Component) GracefulStop(ctx context.Context) error {
for {
select {
case <-ctx.Done():
return ctx.Err()
err := ctx.Err()
if err != nil {
return fmt.Errorf("egrpc GracefulStop, err: %w", err)
}
return nil
case <-c.quit:
return nil
}
Expand Down
3 changes: 3 additions & 0 deletions test/gracefulstop/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[server.http]
port = 9001
host = "0.0.0.0"
5 changes: 5 additions & 0 deletions test/gracefulstop/gracefulstop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
构造一个接口需要响应5s
发送信号量 kill -s SIGTERM PID

curl http://127.0.0.1:9001/hello
kill -s SIGTERM 53065
25 changes: 25 additions & 0 deletions test/gracefulstop/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package main

import (
"time"

"github.com/gin-gonic/gin"
"github.com/gotomicro/ego"
"github.com/gotomicro/ego/core/elog"
"github.com/gotomicro/ego/server/egin"
)

// export EGO_DEBUG=true && go run main.go --config=config.toml
func main() {
if err := ego.New().Serve(func() *egin.Component {
server := egin.Load("server.http").Build()
server.GET("/hello", func(ctx *gin.Context) {
time.Sleep(time.Second * 4)
ctx.JSON(200, "Hello EGO")
return

Check failure on line 19 in test/gracefulstop/main.go

View workflow job for this annotation

GitHub Actions / lint

S1023: redundant `return` statement (gosimple)
})
return server
}()).Run(); err != nil {
elog.Panic("startup", elog.FieldErr(err))
}
}

0 comments on commit 3046864

Please sign in to comment.