From af763d4e1411e29f96c0d22a90099e87ea5e526c Mon Sep 17 00:00:00 2001 From: GoshaDozoretz Date: Sun, 9 Jul 2023 18:34:35 +0300 Subject: [PATCH] fix: server managing improvements - RK-19210 (#88) * feat: add gracefull shutdown Signed-off-by: Gosha * feat: add logs Signed-off-by: Gosha * fix: update git signture in tests Signed-off-by: Gosha * fix: better server handler Signed-off-by: Gosha * fix: improved server managment Signed-off-by: Gosha * fix: improved server managment Signed-off-by: Gosha * fix: improved server managment Signed-off-by: Gosha * fix: improved server managment Signed-off-by: Gosha * fix: improved server managment Signed-off-by: Gosha * fix: graceful shutdown handler Signed-off-by: Gosha * fix: graceful shutdown handler Signed-off-by: Gosha * fix: graceful shutdown handler Signed-off-by: Gosha --------- Signed-off-by: Gosha --- cmd/piper/piper.go | 10 +++- go.mod | 4 +- go.sum | 15 ++++++ pkg/event_handler/main.go | 3 +- pkg/server/main.go | 24 ++++++++++ pkg/server/routes/healthz.go | 4 +- pkg/server/server.go | 88 ++++++++++++------------------------ pkg/server/shutdown.go | 46 +++++++++++++++++++ pkg/server/types.go | 21 +++++++++ 9 files changed, 148 insertions(+), 67 deletions(-) create mode 100644 pkg/server/main.go create mode 100644 pkg/server/shutdown.go create mode 100644 pkg/server/types.go diff --git a/cmd/piper/piper.go b/cmd/piper/piper.go index a779295f..7db7b84f 100644 --- a/cmd/piper/piper.go +++ b/cmd/piper/piper.go @@ -9,7 +9,10 @@ import ( "github.com/rookout/piper/pkg/server" "github.com/rookout/piper/pkg/utils" workflowHandler "github.com/rookout/piper/pkg/workflow_handler" + "golang.org/x/net/context" "log" + "os/signal" + "syscall" ) func main() { @@ -50,6 +53,9 @@ func main() { panic(err) } - event_handler.Start(cfg, globalClients) - server.Start(cfg, globalClients) + // Create context that listens for the interrupt signal from the OS. + ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) + defer stop() + event_handler.Start(ctx, stop, cfg, globalClients) + server.Start(ctx, stop, cfg, globalClients) } diff --git a/go.mod b/go.mod index 386539bd..f8b5a66d 100644 --- a/go.mod +++ b/go.mod @@ -50,6 +50,7 @@ require ( github.com/kr/pretty v0.3.1 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -57,6 +58,7 @@ require ( github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rs/zerolog v1.29.1 // indirect github.com/sirupsen/logrus v1.9.2 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect @@ -66,7 +68,7 @@ require ( golang.org/x/crypto v0.9.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sys v0.8.0 // indirect + golang.org/x/sys v0.10.0 // indirect golang.org/x/term v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect golang.org/x/time v0.3.0 // indirect diff --git a/go.sum b/go.sum index cfdc6704..9f2c75d1 100644 --- a/go.sum +++ b/go.sum @@ -79,6 +79,7 @@ github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUK github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -141,6 +142,7 @@ github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -272,6 +274,11 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= @@ -310,6 +317,9 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= +github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -511,15 +521,20 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= diff --git a/pkg/event_handler/main.go b/pkg/event_handler/main.go index 36c666c8..d4ce1a1b 100644 --- a/pkg/event_handler/main.go +++ b/pkg/event_handler/main.go @@ -9,8 +9,7 @@ import ( "log" ) -func Start(cfg *conf.GlobalConfig, clients *clients.Clients) { - ctx := context.Background() // TODO: use global context that initialized at main +func Start(ctx context.Context, stop context.CancelFunc, cfg *conf.GlobalConfig, clients *clients.Clients) { labelSelector := &metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ {Key: "piper.rookout.com/notified", diff --git a/pkg/server/main.go b/pkg/server/main.go new file mode 100644 index 00000000..60506130 --- /dev/null +++ b/pkg/server/main.go @@ -0,0 +1,24 @@ +package server + +import ( + "github.com/rookout/piper/pkg/clients" + "github.com/rookout/piper/pkg/conf" + "golang.org/x/net/context" + "log" +) + +func Start(ctx context.Context, stop context.CancelFunc, cfg *conf.GlobalConfig, clients *clients.Clients) { + + srv := NewServer(cfg, clients) + gracefulShutdownHandler := NewGracefulShutdown(ctx, stop) + httpServer := srv.ListenAndServe() + + err := clients.GitProvider.SetWebhook() + if err != nil { + panic(err) + } + + gracefulShutdownHandler.Shutdown(httpServer, clients) + + log.Println("Server exiting") +} diff --git a/pkg/server/routes/healthz.go b/pkg/server/routes/healthz.go index 567fca5f..80c341cf 100644 --- a/pkg/server/routes/healthz.go +++ b/pkg/server/routes/healthz.go @@ -3,12 +3,10 @@ package routes import ( "net/http" - "github.com/rookout/piper/pkg/conf" - "github.com/gin-gonic/gin" ) -func AddHealthRoutes(cfg *conf.GlobalConfig, rg *gin.RouterGroup) { +func AddHealthRoutes(rg *gin.RouterGroup) { health := rg.Group("/healthz") health.GET("", func(c *gin.Context) { diff --git a/pkg/server/server.go b/pkg/server/server.go index 18ab8c28..cf92397f 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -1,90 +1,60 @@ package server import ( - "context" "github.com/gin-gonic/gin" "github.com/rookout/piper/pkg/clients" "github.com/rookout/piper/pkg/conf" "github.com/rookout/piper/pkg/server/routes" "log" "net/http" - "os/signal" - "syscall" - "time" ) -func Init() *gin.Engine { - engine := gin.New() - engine.Use( - gin.LoggerWithConfig(gin.LoggerConfig{ - SkipPaths: []string{"/healthz"}, - }), - gin.Recovery(), - ) - return engine -} - -func Start(cfg *conf.GlobalConfig, clients *clients.Clients) { - // Create context that listens for the interrupt signal from the OS. - ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) - defer stop() - - router := Init() +func NewServer(config *conf.GlobalConfig, clients *clients.Clients) *Server { + srv := &Server{ + router: gin.New(), + config: config, + clients: clients, + } - getRoutes(cfg, clients, router) + return srv +} +func (s *Server) startServer() *http.Server { srv := &http.Server{ Addr: ":8080", - Handler: router, + Handler: s.router, } - // Initializing the server in a goroutine so that - // it won't block the graceful shutdown handling below go func() { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("listen: %s\n", err) } }() - err := clients.GitProvider.SetWebhook() - if err != nil { - panic(err) - } - - // Listen for the interrupt signal. - <-ctx.Done() - - // Restore default behavior on the interrupt signal and notify user of shutdown. - stop() - log.Println("shutting down gracefully...") - - // The context is used to inform the server it has 10 seconds to finish - // the request it is currently handling - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - _ = gracefulShutdownHandler(&ctx, clients) + return srv +} - err = srv.Shutdown(ctx) - if err != nil { - log.Fatal("Server forced to shutdown: ", err) - } +func (s *Server) registerMiddlewares() { + s.router.Use( + gin.LoggerWithConfig(gin.LoggerConfig{ + SkipPaths: []string{"/healthz"}, + }), + gin.Recovery(), + ) - log.Println("Server exiting") } -func getRoutes(cfg *conf.GlobalConfig, clients *clients.Clients, router *gin.Engine) { - v1 := router.Group("/") - routes.AddHealthRoutes(cfg, v1) - routes.AddWebhookRoutes(cfg, clients, v1) +func (s *Server) getRoutes() { + v1 := s.router.Group("/") + routes.AddHealthRoutes(v1) + routes.AddWebhookRoutes(s.config, s.clients, v1) } -func gracefulShutdownHandler(ctx *context.Context, clients *clients.Clients) error { - err := clients.GitProvider.UnsetWebhook(ctx) - if err != nil { - log.Println("Unset webhook error: ", err) // ERROR - return err - } +func (s *Server) ListenAndServe() *http.Server { + + s.registerMiddlewares() + + s.getRoutes() - return nil + return s.startServer() } diff --git a/pkg/server/shutdown.go b/pkg/server/shutdown.go new file mode 100644 index 00000000..0562a2f0 --- /dev/null +++ b/pkg/server/shutdown.go @@ -0,0 +1,46 @@ +package server + +import ( + "github.com/rookout/piper/pkg/clients" + "golang.org/x/net/context" + "log" + "net/http" + "time" +) + +type gracefulShutdown struct { + ctx context.Context + stop context.CancelFunc +} + +func NewGracefulShutdown(ctx context.Context, stop context.CancelFunc) *gracefulShutdown { + return &gracefulShutdown{ + ctx: ctx, + stop: stop, + } +} + +func (s *gracefulShutdown) Shutdown(httpServer *http.Server, clients *clients.Clients) { + // Listen for the interrupt signal. + <-s.ctx.Done() + + // Restore default behavior on the interrupt signal and notify user of shutdown. + s.stop() + + log.Println("shutting down gracefully...") + // The context is used to inform the server it has 10 seconds to finish + // the request it is currently handling + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + err := clients.GitProvider.UnsetWebhook(&ctx) + if err != nil { + log.Println("Unset webhook error: ", err) // ERROR + } + + err = httpServer.Shutdown(ctx) + if err != nil { + log.Fatal("Server forced to shutdown: ", err) + } + +} diff --git a/pkg/server/types.go b/pkg/server/types.go new file mode 100644 index 00000000..7b6ecc9d --- /dev/null +++ b/pkg/server/types.go @@ -0,0 +1,21 @@ +package server + +import ( + "github.com/gin-gonic/gin" + "github.com/rookout/piper/pkg/clients" + "github.com/rookout/piper/pkg/conf" + "net/http" +) + +type Server struct { + router *gin.Engine + config *conf.GlobalConfig + clients *clients.Clients +} + +type Interface interface { + startServer() *http.Server + registerMiddlewares() + getRoutes() + ListenAndServe() *http.Server +}