Initial project structure commit.
Static directory for public folders and business logic for the app within internal, split into domain specific folders to keep clear seperation of concerns.
This commit is contained in:
+86
@@ -0,0 +1,86 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"nfeeder/internal/db"
|
||||
"nfeeder/internal/web"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, ctxCancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer ctxCancel()
|
||||
|
||||
// DB init
|
||||
// ------------------------------------------------------------
|
||||
connStr := os.Getenv("DATABASE_URL")
|
||||
if connStr == "" {
|
||||
log.Fatal("DATABASE_URL environment variable is not set")
|
||||
}
|
||||
|
||||
poolConfig, err := pgxpool.ParseConfig(connStr)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to parse DATABASE_URL: %v", err)
|
||||
}
|
||||
|
||||
poolConfig.MaxConns = 25
|
||||
poolConfig.MinConns = 5
|
||||
poolConfig.MaxConnLifetime = 5 * time.Minute
|
||||
poolConfig.MaxConnIdleTime = 30 * time.Second
|
||||
|
||||
pool, err := pgxpool.NewWithConfig(ctx, poolConfig)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to create connection pool: %v", err)
|
||||
}
|
||||
|
||||
// Verify the connection is alive before proceeding
|
||||
if err := pool.Ping(ctx); err != nil {
|
||||
log.Fatalf("Unable to reach database: %v", err)
|
||||
}
|
||||
fmt.Println("Database connection established")
|
||||
|
||||
defer func() {
|
||||
pool.Close()
|
||||
fmt.Println("Database pool closed")
|
||||
}()
|
||||
|
||||
// Create Store sqlc wrapper
|
||||
store := db.NewStore(pool)
|
||||
|
||||
// Server Init
|
||||
// ------------------------------------------------------------
|
||||
server := web.NewServer(store)
|
||||
|
||||
// We run it in a goroutine so it doesn't block main from reaching the signal listener.
|
||||
go func() {
|
||||
addr := ":3000"
|
||||
fmt.Printf("Server starting on %s\n", addr)
|
||||
|
||||
if err := server.Start(addr); err != nil && err != http.ErrServerClosed {
|
||||
log.Fatalf("Server failed: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Graceful Shutdown
|
||||
// ------------------------------------------------------------
|
||||
<-ctx.Done()
|
||||
fmt.Println("\nShutdown signal received. Starting graceful exit...")
|
||||
|
||||
shutdownCtx, shutdownCtxCancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer shutdownCtxCancel()
|
||||
|
||||
if err := server.Shutdown(shutdownCtx); err != nil {
|
||||
log.Fatalf("Graceful shutdown failed: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("Server exited properly")
|
||||
}
|
||||
Reference in New Issue
Block a user