ulflow_phattt2901 f4ef71b63b
Some checks failed
CI Pipeline / Security Scan (push) Failing after 5m24s
CI Pipeline / Lint (push) Failing after 5m30s
CI Pipeline / Test (push) Has been skipped
CI Pipeline / Build (push) Has been skipped
CI Pipeline / Notification (push) Successful in 1s
feat: implement user authentication system with JWT and role-based access control
2025-05-24 11:24:19 +07:00

177 lines
4.7 KiB
Go

package main
import (
"context"
"fmt"
"os"
"time"
"gorm.io/gorm"
"starter-kit/internal/helper/config"
"starter-kit/internal/helper/database"
"starter-kit/internal/helper/feature"
"starter-kit/internal/helper/logger"
"starter-kit/internal/pkg/lifecycle"
"starter-kit/internal/transport/http"
)
// HTTPService implements the lifecycle.Service interface for the HTTP server
type HTTPService struct {
server *http.Server
cfg *config.Config
db *database.Database
}
func NewHTTPService(cfg *config.Config, db *database.Database) *HTTPService {
return &HTTPService{
server: http.NewServer(cfg, db.DB),
cfg: cfg,
db: db,
}
}
func (s *HTTPService) Name() string {
return "HTTP Server"
}
func (s *HTTPService) Start() error {
// Tạo channel để nhận lỗi từ goroutine
errChan := make(chan error, 1)
// Khởi động server trong goroutine
go func() {
logger.Infof("Đang khởi động %s trên %s:%d...", s.Name(), s.cfg.Server.Host, s.cfg.Server.Port)
if err := s.server.Start(); err != nil {
logger.WithError(err).Error("Lỗi HTTP server")
errChan <- fmt.Errorf("lỗi HTTP server: %w", err)
return
}
errChan <- nil
}()
// Chờ server khởi động hoặc báo lỗi
select {
case err := <-errChan:
return err // Trả về lỗi nếu có
case <-time.After(5 * time.Second):
// Nếu sau 5 giây không có lỗi, coi như server đã khởi động thành công
logger.Infof("%s đã khởi động thành công trên %s:%d", s.Name(), s.cfg.Server.Host, s.cfg.Server.Port)
return nil
}
}
func (s *HTTPService) Shutdown(ctx context.Context) error {
return s.server.Shutdown(ctx)
}
func main() {
// Initialize config loader
configLoader := config.NewConfigLoader()
// Load configuration
cfg, err := configLoader.Load()
if err != nil {
fmt.Printf("Failed to load configuration: %v\n", err)
os.Exit(1)
}
// Initialize logger
logger.Init(&logger.LogConfig{
Level: cfg.Logger.Level,
Format: "json",
EnableCaller: true,
ReportCaller: true,
})
// Initialize feature flags
if err := feature.Init(); err != nil {
logger.WithError(err).Fatal("Failed to initialize feature flags")
}
// Print application info
logger.Infof("Starting %s v%s", cfg.App.Name, cfg.App.Version)
logger.Infof("Environment: %s", cfg.App.Environment)
logger.Infof("Log Level: %s", cfg.Logger.Level)
logger.Infof("Timezone: %s", cfg.App.Timezone)
// Print server config
logger.Infof("Server config: %s:%d", cfg.Server.Host, cfg.Server.Port)
logger.Infof("Read Timeout: %d seconds", cfg.Server.ReadTimeout)
logger.Infof("Write Timeout: %d seconds", cfg.Server.WriteTimeout)
logger.Infof("Shutdown Timeout: %d seconds", cfg.Server.ShutdownTimeout)
// Create a new lifecycle manager
shutdownTimeout := 30 * time.Second // Default shutdown timeout
if cfg.Server.ShutdownTimeout > 0 {
shutdownTimeout = time.Duration(cfg.Server.ShutdownTimeout) * time.Second
}
lifecycleMgr := lifecycle.New(shutdownTimeout)
// Initialize database connection
db, err := database.NewConnection(&cfg.Database)
if err != nil {
logger.WithError(err).Fatal("Failed to connect to database")
}
// Run database migrations
if err := database.Migrate(cfg.Database); err != nil {
logger.WithError(err).Fatal("Failed to migrate database")
}
// Register database cleanup on shutdown
lifecycleMgr.Register(&databaseService{db: db})
// Initialize HTTP service with database
httpService := NewHTTPService(cfg, &database.Database{DB: db})
if httpService == nil {
logger.Fatal("Failed to create HTTP service")
}
lifecycleMgr.Register(httpService)
// Start all services
logger.Info("Đang khởi động các dịch vụ...")
if err := lifecycleMgr.Start(); err != nil {
logger.WithError(err).Fatal("Lỗi nghiêm trọng: Không thể khởi động các dịch vụ")
}
// Handle OS signals for graceful shutdown in a separate goroutine
go lifecycleMgr.ShutdownOnSignal()
// Wait for all services to complete
if err := lifecycleMgr.Wait(); err != nil {
logger.WithError(err).Error("Service error")
}
// Close feature flags
if err := feature.Close(); err != nil {
logger.WithError(err).Error("Failed to close feature flags")
}
logger.Info("Application stopped")
}
// databaseService implements the lifecycle.Service interface for database operations
type databaseService struct {
db *gorm.DB
}
func (s *databaseService) Name() string {
return "Database Service"
}
func (s *databaseService) Start() error {
// Database initialization is handled in main
return nil
}
func (s *databaseService) Shutdown(ctx context.Context) error {
if s.db != nil {
sqlDB, err := s.db.DB()
if err != nil {
return fmt.Errorf("failed to get database instance: %w", err)
}
return sqlDB.Close()
}
return nil
}