add application run and stop

This commit is contained in:
yash 2024-01-25 15:35:04 +03:00
parent d0bb3001f4
commit 29686ee798
6 changed files with 128 additions and 11 deletions

View File

@ -5,6 +5,7 @@ import (
"log/slog" "log/slog"
"os" "os"
"os/signal" "os/signal"
"recipes/internal/app"
"recipes/internal/config" "recipes/internal/config"
"syscall" "syscall"
@ -19,7 +20,6 @@ const (
//TODO //TODO
// cache // cache
// http server
// app // app
// graceful sd // graceful sd
// tests // tests
@ -34,6 +34,9 @@ func main() {
log.Debug("Application config", slog.Any("config", fmt.Sprintf("%+v", *cfg))) log.Debug("Application config", slog.Any("config", fmt.Sprintf("%+v", *cfg)))
// init app (storage, cache, media storage) // init app (storage, cache, media storage)
application := app.New(log, cfg)
// start app
go application.HTTPSrv.MustRun()
// graceful shutdown // graceful shutdown
stop := make(chan os.Signal, 1) stop := make(chan os.Signal, 1)
@ -43,7 +46,7 @@ func main() {
log.Info("stopping application...") log.Info("stopping application...")
// application.GRPCSrv.Stop() application.HTTPSrv.Stop()
log.Info("application stopped") log.Info("application stopped")
} }

31
internal/app/app.go Normal file
View File

@ -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}
}

View File

@ -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()
}

View File

@ -11,11 +11,7 @@ import (
type Config struct { type Config struct {
Env string `yaml:"env" env-required:"true"` Env string `yaml:"env" env-required:"true"`
HTTPServer struct { HTTPServerConfig `yaml:"http-server"`
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"`
Postgresql struct { Postgresql struct {
DBName string `yaml:"db_name" env-required:"true"` DBName string `yaml:"db_name" env-required:"true"`
User string `yaml:"user" env-required:"true"` User string `yaml:"user" env-required:"true"`
@ -33,6 +29,12 @@ type Config struct {
} `yaml:"minio"` } `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. // MustLoad returns config or panic.
func MustLoad() *Config { func MustLoad() *Config {
configPath := fetchConfigPath() configPath := fetchConfigPath()

View File

@ -63,7 +63,6 @@ func New(log *slog.Logger, recipesProvider RecipesProvider) http.HandlerFunc {
return return
} }
// return // return
// return
render.JSON(w, r, Response{ render.JSON(w, r, Response{
Response: resp.OK(), Response: resp.OK(),
Recipes: recipes, Recipes: recipes,

View File

@ -1,4 +1,4 @@
package middleware package logger
import ( import (
"log/slog" "log/slog"