121 lines
3.0 KiB
Go
121 lines
3.0 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"time"
|
|
|
|
"git.farahty.com/nimer/go-mongo/app"
|
|
|
|
"github.com/fatih/color"
|
|
"github.com/joho/godotenv"
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
func main() {
|
|
// Setup cancelable root context
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
// Panic recovery
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
color.Red("🔴 Panic occurred: %v\n", r)
|
|
os.Exit(1)
|
|
}
|
|
}()
|
|
|
|
color.Yellow("🚀 Starting server ...\n")
|
|
|
|
// Load .env if needed
|
|
if _, exists := os.LookupEnv("MONGO_URI"); !exists {
|
|
if err := godotenv.Load(); err != nil {
|
|
log.Fatal("🔴 Failed to load .env file: ", err)
|
|
}
|
|
color.Green("✅ .env file loaded\n")
|
|
}
|
|
|
|
// Validate environment variables
|
|
requiredEnvs := []string{"PORT", "MONGO_URI", "REDIS_HOST", "REDIS_PORT"}
|
|
for _, key := range requiredEnvs {
|
|
if os.Getenv(key) == "" {
|
|
log.Fatalf("🔴 Required environment variable %s is missing", key)
|
|
}
|
|
}
|
|
port := os.Getenv("PORT")
|
|
|
|
// Connect to Mongo
|
|
dbCancel, err := app.Connect()
|
|
if err != nil {
|
|
log.Fatalf("🔴 MongoDB connection error: %v", err)
|
|
}
|
|
defer func() {
|
|
color.Red("❌ Closing MongoDB connection...\n")
|
|
dbCancel()
|
|
if err := app.Mongo.Disconnect(ctx); err != nil {
|
|
log.Fatal("🔴 MongoDB disconnection error: ", err)
|
|
}
|
|
}()
|
|
color.Green("✅ Connected to MongoDB successfully\n")
|
|
|
|
// Load authorization policies using root context
|
|
if err := app.LoadAuthorizer(ctx); err != nil {
|
|
log.Fatal("🔴 Authorizer error: ", err)
|
|
}
|
|
color.Green("✅ Authorization policies loaded successfully\n")
|
|
|
|
// Redis
|
|
redisClient := redis.NewClient(&redis.Options{
|
|
Addr: os.Getenv("REDIS_HOST") + ":" + os.Getenv("REDIS_PORT"),
|
|
Password: os.Getenv("REDIS_PASSWORD"),
|
|
DB: 0,
|
|
})
|
|
if _, err := redisClient.Ping(ctx).Result(); err != nil {
|
|
log.Fatal("🔴 Redis connection error: ", err)
|
|
}
|
|
defer func() {
|
|
color.Red("❌ Closing Redis connection...\n")
|
|
_ = redisClient.Close()
|
|
}()
|
|
color.Green("✅ Connected to Redis cache successfully\n")
|
|
|
|
// Create GraphQL server
|
|
graphqlServer := createGraphqlServer(redisClient)
|
|
|
|
// Start HTTP server
|
|
server := &http.Server{
|
|
Addr: ":" + port,
|
|
Handler: createRouter(graphqlServer),
|
|
ReadTimeout: 30 * time.Second,
|
|
WriteTimeout: 30 * time.Second,
|
|
IdleTimeout: 30 * time.Second,
|
|
}
|
|
|
|
go func() {
|
|
color.Green("🌐 Server listening at http://localhost:%s\n", port)
|
|
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
log.Fatalf("🔴 Server failed: %v", err)
|
|
}
|
|
}()
|
|
|
|
// Graceful shutdown
|
|
quit := make(chan os.Signal, 1)
|
|
signal.Notify(quit, os.Interrupt)
|
|
<-quit
|
|
|
|
color.Yellow("🟡 Shutdown signal received, initiating cleanup...")
|
|
|
|
// Cancel root context and wait for graceful shutdown
|
|
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
defer shutdownCancel()
|
|
|
|
if err := server.Shutdown(shutdownCtx); err != nil {
|
|
log.Fatalf("🔴 Server forced to shutdown: %v", err)
|
|
}
|
|
|
|
color.Green("✅ Server shutdown completed gracefully")
|
|
}
|