1
0
Fork 0
This repository has been archived on 2025-08-23. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
mareshq-backoffice-v2-api/internal/server/server.go
2024-05-04 18:21:45 +02:00

145 lines
3.2 KiB
Go

package server
import (
"context"
"os"
"os/signal"
"sync"
"syscall"
"time"
fiberzap "github.com/gofiber/contrib/fiberzap/v2"
"github.com/gofiber/contrib/swagger"
"github.com/gofiber/fiber/v2"
middleware "github.com/oapi-codegen/fiber-middleware"
"gitlab.mareshq.com/hq/backoffice/backoffice-api/internal/api"
"go.uber.org/zap"
)
type Server struct {
ready ready
}
func NewServer() *Server {
return &Server{}
}
func (s *Server) Run() {
shutdownCtx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
logger, err := zap.NewProduction()
if err != nil {
logger.Fatal("failed to initialize logger", zap.Error(err))
}
defer logger.Sync()
sugaredLogger := logger.Sugar()
fiberConfig := fiber.Config{
ReadTimeout: 5 * time.Second,
WriteTimeout: 5 * time.Second,
IdleTimeout: 5 * time.Second,
DisableStartupMessage: true,
}
app := fiber.New(fiberConfig)
app.Get("/", func(c *fiber.Ctx) error {
return c.SendStatus(fiber.StatusNotFound)
})
app.Get("/livez", func(c *fiber.Ctx) error {
return c.SendStatus(fiber.StatusOK)
})
app.Get("/readyz", func(c *fiber.Ctx) error {
if s.ready.isReady() {
return c.SendStatus(fiber.StatusOK)
}
return c.SendStatus(fiber.StatusServiceUnavailable)
})
// TODO: add /metrics endpoint
app.Use(fiberzap.New(fiberzap.Config{
Logger: logger,
}))
swaggerConfig := swagger.Config{
BasePath: "/",
FilePath: "./api/v1/openapi.yaml",
Path: "/swagger",
Title: "Swagger API Docs",
}
app.Use(swagger.New(swaggerConfig))
app = registerAPIHandlers(app, sugaredLogger)
<-shutdownCtx.Done()
stop()
s.ready.notReady()
// wait till Pod is signaling not ready (no new requests)
time.Sleep(5 * time.Second)
shutdownBegan := time.Now()
sugaredLogger.Info("Shutdown signal recieved. Shutting down gracefully...")
// * Gracefully shut down fiber server
// * If does not shutdown within `gracefulShutdownPeriod`, force shutdown
// ! Does not close keep-alive connections
// ! fiber.Config{ReadTimeout} must be set and non-zero and greater than the `gracefulShutdownPeriod`
// TODO: make shutdown timeout configurable
err = app.ShutdownWithTimeout(time.Second * 10)
if err != nil {
sugaredLogger.Errorw("Error during shutdown", "error", err)
}
sugaredLogger.Infof("Shutdown completed in %v", time.Since(shutdownBegan))
}
func registerAPIHandlers(fiberApp *fiber.App, logger *zap.SugaredLogger) *fiber.App {
swagger, err := api.GetSwagger()
if err != nil {
logger.Fatalf("Error getting swagger: %v", err)
}
// TODO: validate this. Copied from example
// See: https://github.com/deepmap/oapi-codegen/blob/master/examples/petstore-expanded/fiber/petstore.go#L41
// Clear out the servers array in the swagger spec, that skips validating
// that server names match. We don't know how this thing will be run.
swagger.Servers = nil
fiberApp.Use(middleware.OapiRequestValidator(swagger))
api.RegisterHandlers(fiberApp)
return fiberApp
}
type ready struct {
ready bool
lock sync.Mutex
}
func (r *ready) setReady() {
r.lock.Lock()
defer r.lock.Unlock()
r.ready = true
}
func (r *ready) isReady() bool {
r.lock.Lock()
defer r.lock.Unlock()
return r.ready
}
func (r *ready) notReady() {
r.lock.Lock()
defer r.lock.Unlock()
r.ready = false
}