-
Notifications
You must be signed in to change notification settings - Fork 0
refactor: improve backend code quality and security #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
07db321
01eff7c
18dd33e
5f9cd92
77c3312
7c9df5b
9bf93f0
3743b8e
09edfaa
8739e22
27cb619
2333d54
5a8b43a
420c053
4a9f009
ba1de3d
4ee8fa7
8a8f845
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,7 +10,7 @@ import ( | |
| "backend/internal/health" | ||
| "context" | ||
| "fmt" | ||
| "log" | ||
| "log/slog" | ||
| "net/http" | ||
| "os" | ||
| "os/signal" | ||
|
|
@@ -23,7 +23,7 @@ import ( | |
| ) | ||
|
|
||
| const ( | ||
| gracefulShutdownTimeout = 5 * time.Second | ||
| defaultShutdownTimeout = 5 * time.Second | ||
| ) | ||
|
|
||
| // @title Backend API | ||
|
|
@@ -38,22 +38,28 @@ func main() { | |
| // Load configuration | ||
| cfg, err := config.LoadConfig() | ||
| if err != nil { | ||
| log.Fatalf("Failed to load configuration: %v", err) | ||
| slog.Error("Failed to load configuration", "error", err) | ||
| os.Exit(1) | ||
| } | ||
|
|
||
| // Initialize database | ||
| db, err := database.NewFromAppConfig(cfg) | ||
| // Initialize repository using the factory (selects MySQL or Azure Table based on config) | ||
| repo, err := database.NewRepository(cfg) | ||
| if err != nil { | ||
| log.Fatalf("Failed to initialize database: %v", err) | ||
| slog.Error("Failed to initialize repository", "error", err) | ||
| os.Exit(1) | ||
| } | ||
|
|
||
| // Initialize health checker | ||
| // Initialize health checker with actual database dependency | ||
| healthChecker := health.New() | ||
| healthChecker.AddCheck("database", db.Ping) | ||
| healthChecker.AddCheck("database", func(ctx context.Context) error { | ||
| return repo.Ping(ctx) | ||
| }) | ||
| healthChecker.SetReady(true) | ||
|
|
||
| // Setup router | ||
| router := gin.Default() | ||
| routes.SetupRoutes(router, db) | ||
| // Setup router — use gin.New() since SetupRoutes registers its own Logger and Recovery middleware. | ||
| router := gin.New() | ||
| rateLimiter := routes.SetupRoutes(router, repo, healthChecker, cfg) | ||
| defer rateLimiter.Stop() | ||
| router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) | ||
|
|
||
| // Create server with timeouts | ||
|
|
@@ -67,29 +73,38 @@ func main() { | |
|
|
||
| // Start server in a goroutine | ||
| go func() { | ||
| slog.Info("Server starting", "addr", srv.Addr) | ||
| if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { | ||
| log.Fatalf("Failed to start server: %v", err) | ||
| slog.Error("Failed to start server", "error", err) | ||
| os.Exit(1) | ||
| } | ||
| }() | ||
|
|
||
| // Wait for interrupt signal | ||
| quit := make(chan os.Signal, 1) | ||
| signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) | ||
| <-quit | ||
| log.Println("Shutting down server...") | ||
| slog.Info("Shutting down server...") | ||
|
|
||
| // Give outstanding requests 5 seconds to complete | ||
| ctx, cancel := context.WithTimeout(context.Background(), gracefulShutdownTimeout) | ||
| // Give outstanding requests time to complete | ||
| shutdownTimeout := cfg.Server.ShutdownTimeout | ||
| if shutdownTimeout == 0 { | ||
| shutdownTimeout = defaultShutdownTimeout | ||
| } | ||
| ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout) | ||
| defer cancel() | ||
|
|
||
| err = srv.Shutdown(ctx) | ||
| // Always execute cleanup | ||
| cancel() | ||
|
|
||
| // Close repository connections (database pool, etc.) | ||
| if closeErr := repo.Close(); closeErr != nil { | ||
| slog.Error("Failed to close repository", "error", closeErr) | ||
| } | ||
|
|
||
| if err != nil { | ||
| log.Printf("Server forced to shutdown: %v", err) | ||
| return // Return with error status from main | ||
| slog.Error("Server forced to shutdown", "error", err) | ||
| return | ||
| } | ||
|
Comment on lines
97
to
107
|
||
|
|
||
| log.Println("Server exiting") | ||
| slog.Info("Server exited gracefully") | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The database initialization code has been removed (lines 45-50 in old code), but the migration logic that depends on it is not visible in this diff. If migrations are still needed, they should be run after the repository is created. Verify that AutoMigrate() is still being called somewhere, or document that migrations are now optional when using Azure Table Storage.