Skip to content

Commit

Permalink
merge develop
Browse files Browse the repository at this point in the history
  • Loading branch information
HermanPlay committed Dec 26, 2024
2 parents 87cf6b1 + 2396014 commit 068d3b5
Show file tree
Hide file tree
Showing 17 changed files with 303 additions and 63 deletions.
13 changes: 8 additions & 5 deletions cmd/app/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import (
"os"

"github.com/joho/godotenv"
_ "github.com/mini-maxit/backend/docs"
"github.com/mini-maxit/backend/internal/api/http/initialization"
"github.com/mini-maxit/backend/internal/api/http/server"
"github.com/mini-maxit/backend/internal/config"
"github.com/sirupsen/logrus"
_ "github.com/mini-maxit/backend/docs"
"github.com/mini-maxit/backend/internal/logger"
)

// @title Mini Maxit API Documentation testing the workflow
Expand All @@ -27,18 +27,21 @@ func main() {

initialization := initialization.NewInitialization(cfg)

logger.InitializeLogger()
server_logger := logger.NewNamedLogger("server")

queueListener := initialization.QueueListener
cancel, err := queueListener.Start()
if err != nil {
logrus.Errorf("failed to start queue listener: %v", err)
logger.Log(&server_logger, "failed to start queue listener:", err.Error(), logger.Error)
os.Exit(1)
}

server := server.NewServer(initialization)
server := server.NewServer(initialization, &server_logger)
err = server.Start()
if err != nil {
cancel() // Stop the queue listener
logrus.Errorf("server exited with error: %v", err)
logger.Log(&server_logger, "failed to start server:", err.Error(), logger.Error)
os.Exit(1)

}
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ require (
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.9.0
github.com/swaggo/swag v1.16.4
go.uber.org/zap v1.27.0
golang.org/x/crypto v0.29.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/validator.v2 v2.0.1
)

Expand All @@ -27,6 +29,7 @@ require (
github.com/mailru/easyjson v0.7.7 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/sync v0.9.0 // indirect
golang.org/x/tools v0.27.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A=
github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
Expand All @@ -68,6 +72,8 @@ golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/validator.v2 v2.0.1 h1:xF0KWyGWXm/LM2G1TrEjqOu4pa6coO9AlWSf3msVfDY=
gopkg.in/validator.v2 v2.0.1/go.mod h1:lIUZBlB3Im4s/eYp39Ry/wkR02yOPhZ9IwIRBjuPuG8=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down
32 changes: 18 additions & 14 deletions internal/api/http/initialization/initialization.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/mini-maxit/backend/internal/api/queue"
"github.com/mini-maxit/backend/internal/config"
"github.com/mini-maxit/backend/internal/database"
"github.com/mini-maxit/backend/internal/logger"
"github.com/mini-maxit/backend/package/repository"
"github.com/mini-maxit/backend/package/service"
"github.com/mini-maxit/backend/package/utils"
Expand All @@ -33,34 +34,37 @@ type Initialization struct {
}

func connectToBroker(cfg *config.Config) (*amqp.Connection, *amqp.Channel) {
broker_logger := logger.NewNamedLogger("connect_to_broker")

var err error
var conn *amqp.Connection
for v := range 5 {
conn, err = amqp.Dial(fmt.Sprintf("amqp://%s:%s@%s:%d/", cfg.BrokerConfig.User, cfg.BrokerConfig.Password, cfg.BrokerConfig.Host, cfg.BrokerConfig.Port))
if err != nil {
logrus.Printf("Failed to connect to RabbitMQ: %v\nRetrying...", err)
logger.Log(&broker_logger, "Failed to connect to RabbitMQ:", err.Error(), logger.Warn)
time.Sleep(2*time.Second + time.Duration(v))
continue
}
}
logrus.Printf("Connected to RabbitMQ")

if err != nil {
panic(fmt.Errorf("failed to connect to RabbitMQ: %w", err))
logger.Log(&broker_logger, "Failed to connect to RabbitMQ:", err.Error(), logger.Panic)
}
channel, err := conn.Channel()
if err != nil {
panic(fmt.Errorf("failed to create channel: %w", err))
logger.Log(&broker_logger, "Failed to create channel:", err.Error(), logger.Panic)
}

return conn, channel
}

func NewInitialization(cfg *config.Config) *Initialization {
init_logger := logger.NewNamedLogger("initialization")
conn, channel := connectToBroker(cfg)
db, err := database.NewPostgresDB(cfg)
if err != nil {
panic(fmt.Errorf("failed to connect to database: %w", err))
logger.Log(&init_logger, "Failed to connect to database:", err.Error(), logger.Panic)
}
tx, err := db.Connect()

Expand All @@ -72,35 +76,35 @@ func NewInitialization(cfg *config.Config) *Initialization {
// Repositories
_, err = repository.NewLanguageRepository(tx)
if err != nil {
panic(fmt.Errorf("failed to create language repository: %w", err))
logger.Log(&init_logger, "Failed to create language repository:", err.Error(), logger.Panic)
}
userRepository, err := repository.NewUserRepository(tx)
if err != nil {
panic(fmt.Errorf("failed to create user repository: %w", err))
logger.Log(&init_logger, "Failed to create user repository:", err.Error(), logger.Panic)
}
taskRepository, err := repository.NewTaskRepository(tx)
if err != nil {
panic(fmt.Errorf("failed to create task repository: %w", err))
logger.Log(&init_logger, "Failed to create task repository:", err.Error(), logger.Panic)
}
_, err = repository.NewGroupRepository(tx)
if err != nil {
panic(fmt.Errorf("failed to create group repository: %w", err))
logger.Log(&init_logger, "Failed to create group repository:", err.Error(), logger.Panic)
}
submissionRepository, err := repository.NewSubmissionRepository(tx)
if err != nil {
panic(fmt.Errorf("failed to create submission repository: %w", err))
logger.Log(&init_logger, "Failed to create submission repository:", err.Error(), logger.Panic)
}
_, err = repository.NewSubmissionResultRepository(tx)
if err != nil {
panic(fmt.Errorf("failed to create submission result repository: %w", err))
logger.Log(&init_logger, "Failed to create submission result repository:", err.Error(), logger.Panic)
}
queueRepository, err := repository.NewQueueMessageRepository(tx)
if err != nil {
panic(fmt.Errorf("failed to create queue repository: %w", err))
logger.Log(&init_logger, "Failed to create queue repository:", err.Error(), logger.Panic)
}
sessionRepository, err := repository.NewSessionRepository(tx)
if err != nil {
panic(fmt.Errorf("failed to create session repository: %w", err))
logger.Log(&init_logger, "Failed to create session repository:", err.Error(), logger.Panic)
}

if err := db.Commit(); err != nil {
Expand All @@ -112,7 +116,7 @@ func NewInitialization(cfg *config.Config) *Initialization {
taskService := service.NewTaskService(cfg, taskRepository, submissionRepository)
queueService, err := service.NewQueueService(taskRepository, submissionRepository, queueRepository, conn, channel, cfg.BrokerConfig.QueueName, cfg.BrokerConfig.ResponseQueueName)
if err != nil {
panic(fmt.Errorf("failed to create queue service: %w", err))
logger.Log(&init_logger, "Failed to create queue service:", err.Error(), logger.Panic)
}
sessionService := service.NewSessionService(sessionRepository, userRepository)
authService := service.NewAuthService(userRepository, sessionService)
Expand All @@ -127,7 +131,7 @@ func NewInitialization(cfg *config.Config) *Initialization {
// Queue listener
queueListener, err := queue.NewQueueListener(conn, channel, taskService, cfg.BrokerConfig.ResponseQueueName)
if err != nil {
panic(fmt.Errorf("failed to create queue listener: %w", err))
logger.Log(&init_logger, "Failed to create queue listener:", err.Error(), logger.Panic)
}

return &Initialization{Cfg: cfg,
Expand Down
6 changes: 3 additions & 3 deletions internal/api/http/middleware/log.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package middleware

import (
"log"
"net/http"
"time"
"go.uber.org/zap"
)

// LoggingMiddleware logs details of each HTTP request.
func LoggingMiddleware(next http.Handler) http.Handler {
func LoggingMiddleware(next http.Handler, log *zap.SugaredLogger) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()

Expand All @@ -16,6 +16,6 @@ func LoggingMiddleware(next http.Handler) http.Handler {
if r.TLS != nil {
protocol = "https"
}
log.Printf("method=%s path=%s host=%s service=%dms bytes=%d protocol=%s", r.Method, r.URL.Path, r.URL.Hostname(), time.Since(start).Milliseconds(), r.ContentLength, protocol)
log.Infof("method=%s path=%s host=%s service=%dms bytes=%d protocol=%s", r.Method, r.URL.Path, r.URL.Hostname(), time.Since(start).Milliseconds(), r.ContentLength, protocol)
})
}
8 changes: 4 additions & 4 deletions internal/api/http/middleware/recovery.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package middleware

import (
"log"
"net/http"

"github.com/mini-maxit/backend/internal/logger"
)

// RecoveryMiddleware recovers from panics and returns a 500 error.
func RecoveryMiddleware(next http.Handler) http.Handler {
func RecoveryMiddleware(next http.Handler, log *logger.ServiceLogger) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if rec := recover(); rec != nil {

// TODO: Create panic logger like the one in worker to write the panic to a file
log.Printf("Panic recovered: %v", rec)
logger.Log(log, "Panic recovered:", rec.(string), logger.Error)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
}()
Expand Down
23 changes: 13 additions & 10 deletions internal/api/http/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ import (

"github.com/mini-maxit/backend/internal/api/http/initialization"
"github.com/mini-maxit/backend/internal/api/http/middleware"
"github.com/sirupsen/logrus"
"github.com/mini-maxit/backend/internal/logger"
)

const ApiVersion = "v1"

type Server struct {
mux http.Handler
port uint16
mux http.Handler
port uint16
server_logger *logger.ServiceLogger
}

func (s *Server) Start() error {
Expand All @@ -32,22 +33,22 @@ func (s *Server) Start() error {
ctx := context.Background()
go func() {
<-sigChan
logrus.Info("Shutting down server...")
logger.Log(s.server_logger, "Shutting down server...", "", logger.Info)

// Create a context with timeout to allow graceful shutdown
shutdownCtx, shutdownCancel := context.WithTimeout(ctx, 5*time.Second)
defer shutdownCancel()

if err := server.Shutdown(shutdownCtx); err != nil {
logrus.Errorf("Server forced to shutdown: %v", err)
logger.Log(s.server_logger, "Error shutting down server:", err.Error(), logger.Error)
}
}()

logrus.Info("Starting server on port ", s.port)
logger.Log(s.server_logger, fmt.Sprintf("Starting server on port %d", s.port), "", logger.Info)
return http.ListenAndServe(server.Addr, server.Handler)
}

func NewServer(initialization *initialization.Initialization) *Server {
func NewServer(initialization *initialization.Initialization, server_logger *logger.ServiceLogger) *Server {
mux := http.NewServeMux()
apiPrefix := fmt.Sprintf("/api/%s", ApiVersion)

Expand Down Expand Up @@ -102,10 +103,12 @@ func NewServer(initialization *initialization.Initialization) *Server {
apiMux.Handle("/auth/", http.StripPrefix("/auth", authMux))
apiMux.Handle("/", middleware.SessionValidationMiddleware(secureMux, initialization.Db, initialization.SessionService))

// Logging middleware
httpLoger := logger.NewHttpLogger()
loggingMux := http.NewServeMux()
loggingMux.Handle("/", middleware.LoggingMiddleware(apiMux))
loggingMux.Handle("/", middleware.LoggingMiddleware(apiMux, httpLoger))
// Add the API prefix to all routes
mux.Handle(apiPrefix+"/", http.StripPrefix(apiPrefix, middleware.RecoveryMiddleware(middleware.DatabaseMiddleware(loggingMux, initialization.Db))))
mux.Handle(apiPrefix+"/", http.StripPrefix(apiPrefix, middleware.RecoveryMiddleware(middleware.DatabaseMiddleware(loggingMux, initialization.Db), server_logger)))

return &Server{mux: mux, port: initialization.Cfg.App.Port}
return &Server{mux: mux, port: initialization.Cfg.App.Port, server_logger: server_logger}
}
Loading

0 comments on commit 068d3b5

Please sign in to comment.