add application run and stop
This commit is contained in:
parent
d0bb3001f4
commit
29686ee798
|
@ -5,6 +5,7 @@ import (
|
|||
"log/slog"
|
||||
"os"
|
||||
"os/signal"
|
||||
"recipes/internal/app"
|
||||
"recipes/internal/config"
|
||||
"syscall"
|
||||
|
||||
|
@ -19,7 +20,6 @@ const (
|
|||
|
||||
//TODO
|
||||
// cache
|
||||
// http server
|
||||
// app
|
||||
// graceful sd
|
||||
// tests
|
||||
|
@ -34,6 +34,9 @@ func main() {
|
|||
log.Debug("Application config", slog.Any("config", fmt.Sprintf("%+v", *cfg)))
|
||||
|
||||
// init app (storage, cache, media storage)
|
||||
application := app.New(log, cfg)
|
||||
// start app
|
||||
go application.HTTPSrv.MustRun()
|
||||
|
||||
// graceful shutdown
|
||||
stop := make(chan os.Signal, 1)
|
||||
|
@ -43,7 +46,7 @@ func main() {
|
|||
|
||||
log.Info("stopping application...")
|
||||
|
||||
// application.GRPCSrv.Stop()
|
||||
application.HTTPSrv.Stop()
|
||||
|
||||
log.Info("application stopped")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
httpsrv "recipes/internal/app/httpSrv"
|
||||
"recipes/internal/config"
|
||||
"recipes/internal/media_storage/minio"
|
||||
"recipes/internal/storage/postgresql"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
HTTPSrv *httpsrv.App
|
||||
}
|
||||
|
||||
func New(log *slog.Logger, cfg *config.Config) *App {
|
||||
// init storage
|
||||
storage, err := postgresql.New(context.Background(), cfg.Postgresql.User, cfg.Postgresql.Password, cfg.Postgresql.Address, cfg.Postgresql.DBName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// init media storage
|
||||
mstorage, err := minio.New(context.Background(), cfg.Minio.Address, cfg.Minio.User, cfg.Minio.Password)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// init http server
|
||||
httpsrv := httpsrv.New(log, &cfg.HTTPServerConfig, storage, mstorage)
|
||||
// return
|
||||
return &App{HTTPSrv: httpsrv}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package httpsrv
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"recipes/internal/config"
|
||||
"recipes/internal/http-server/handlers/recipe"
|
||||
recipeimage "recipes/internal/http-server/handlers/recipeImage"
|
||||
"recipes/internal/http-server/handlers/recipes"
|
||||
recipes_by_category "recipes/internal/http-server/handlers/recipesByCategory"
|
||||
mwLogger "recipes/internal/http-server/middleware/logger"
|
||||
"recipes/internal/lib/logger/sl"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
log *slog.Logger
|
||||
router *chi.Mux
|
||||
srv *http.Server
|
||||
}
|
||||
|
||||
type Storage interface {
|
||||
recipe.RecipeProvider
|
||||
recipes.RecipesProvider
|
||||
recipes_by_category.RecipesProvider
|
||||
}
|
||||
|
||||
type MediaStorage interface {
|
||||
recipeimage.ImageProvider
|
||||
}
|
||||
|
||||
func New(log *slog.Logger, cfg *config.HTTPServerConfig, storage Storage, mediaStorage MediaStorage) *App {
|
||||
// init router
|
||||
router := chi.NewRouter()
|
||||
// middlewares
|
||||
router.Use(middleware.RequestID)
|
||||
router.Use(mwLogger.New(log))
|
||||
router.Use(middleware.Recoverer)
|
||||
// routes
|
||||
router.Get("/recipe", recipe.New(log, storage))
|
||||
router.Get("/recipes_page", recipes.New(log, storage))
|
||||
router.Get("/recipes_by_category", recipes_by_category.New(log, storage))
|
||||
router.Get("/recipe_img", recipeimage.New(log, mediaStorage))
|
||||
// server config
|
||||
srv := &http.Server{
|
||||
Addr: cfg.Address,
|
||||
Handler: router,
|
||||
ReadTimeout: cfg.Timeout,
|
||||
WriteTimeout: cfg.Timeout,
|
||||
IdleTimeout: cfg.IdleTimeout,
|
||||
}
|
||||
|
||||
return &App{
|
||||
log: log,
|
||||
router: router,
|
||||
srv: srv,
|
||||
}
|
||||
}
|
||||
|
||||
// MustRun starts http server or panic in case of error. Blocking function.
|
||||
func (app *App) MustRun() {
|
||||
const op = "app.httpSrv.Stop"
|
||||
if err := app.srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
app.log.Error("failed to start server", sl.Err(err))
|
||||
panic(err)
|
||||
}
|
||||
app.log.Info("HTTP server stopped")
|
||||
}
|
||||
|
||||
func (app *App) Stop() {
|
||||
const op = "app.httpSrv.Stop"
|
||||
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
err := app.srv.Shutdown(shutdownCtx)
|
||||
if err != nil {
|
||||
app.log.Error("failed to stop server", sl.Err(err))
|
||||
}
|
||||
shutdownCancel()
|
||||
}
|
|
@ -11,11 +11,7 @@ import (
|
|||
|
||||
type Config struct {
|
||||
Env string `yaml:"env" env-required:"true"`
|
||||
HTTPServer struct {
|
||||
Address string `yaml:"address" env-required:"true"`
|
||||
Timeout time.Duration `yaml:"timeout" env-default:"4s"`
|
||||
IdleTimeout time.Duration `yaml:"idle_timeout" env-default:"60s"`
|
||||
} `yaml:"http-server"`
|
||||
HTTPServerConfig `yaml:"http-server"`
|
||||
Postgresql struct {
|
||||
DBName string `yaml:"db_name" env-required:"true"`
|
||||
User string `yaml:"user" env-required:"true"`
|
||||
|
@ -33,6 +29,12 @@ type Config struct {
|
|||
} `yaml:"minio"`
|
||||
}
|
||||
|
||||
type HTTPServerConfig struct {
|
||||
Address string `yaml:"address" env-required:"true"`
|
||||
Timeout time.Duration `yaml:"timeout" env-default:"4s"`
|
||||
IdleTimeout time.Duration `yaml:"idle_timeout" env-default:"60s"`
|
||||
}
|
||||
|
||||
// MustLoad returns config or panic.
|
||||
func MustLoad() *Config {
|
||||
configPath := fetchConfigPath()
|
||||
|
|
|
@ -63,7 +63,6 @@ func New(log *slog.Logger, recipesProvider RecipesProvider) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
// return
|
||||
// return
|
||||
render.JSON(w, r, Response{
|
||||
Response: resp.OK(),
|
||||
Recipes: recipes,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package middleware
|
||||
package logger
|
||||
|
||||
import (
|
||||
"log/slog"
|
Loading…
Reference in New Issue