package server import ( "context" "fmt" "git.0x7f.app/WOJ/woj-server/internal/api/consumer" "git.0x7f.app/WOJ/woj-server/internal/misc/config" "git.0x7f.app/WOJ/woj-server/internal/misc/log" "git.0x7f.app/WOJ/woj-server/internal/model" "git.0x7f.app/WOJ/woj-server/internal/repo/db" "git.0x7f.app/WOJ/woj-server/internal/web/router" "git.0x7f.app/WOJ/woj-server/pkg/utils" "git.0x7f.app/WOJ/woj-server/pkg/zapasynq" "github.com/hibiken/asynq" "github.com/samber/do" "go.uber.org/zap" "net/http" "os" "os/signal" "runtime" "syscall" "time" ) func RunServer(i *do.Injector) error { // Prepare Router conf := do.MustInvoke[config.Service](i).GetConfig() slog := do.MustInvoke[log.Service](i).GetLogger("app.server") routers := do.MustInvoke[router.Service](i).GetRouter() // Create Server addr := fmt.Sprintf("%s:%d", conf.WebServer.Address, conf.WebServer.Port) server := &http.Server{ Addr: addr, Handler: routers, } // Run Server go func() { if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { slog.Fatal("ListenAndServe Failed", zap.Error(err)) } }() // Create Queue queueMux := asynq.NewServeMux() { handler := consumer.NewConsumer(i) queueMux.HandleFunc(model.TypeProblemUpdate, handler.ProblemUpdate) queueMux.HandleFunc(model.TypeSubmitUpdate, handler.SubmitUpdate) } queueSrv := asynq.NewServer( asynq.RedisClientOpt{ Addr: conf.Redis.Address, Password: conf.Redis.Password, DB: conf.Redis.QueueDb, }, asynq.Config{ Concurrency: utils.If(runtime.NumCPU() > 1, runtime.NumCPU()-1, 1), Logger: zapasynq.New(slog), Queues: map[string]int{model.QueueServer: 1}, }, ) // Run Queue if err := queueSrv.Start(queueMux); err != nil { slog.Fatal("queueSrv.Start Failed", zap.Error(err)) } // Handle SIGINT and SIGTERM. quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit slog.Info("Shutting down server ...") // Graceful Shutdown Server ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() err := server.Shutdown(ctx) if err != nil { slog.Warn("Server Shutdown Failed", zap.Error(err)) } // Graceful Shutdown Queue queueSrv.Shutdown() // Graceful Shutdown Database err = do.MustInvoke[db.Service](i).Close() if err != nil { slog.Warn("Database Close Failed", zap.Error(err)) } return err }