tercul-backend/main.go
Damir Mukimov 4957117cb6 Initial commit: Tercul Go project with comprehensive architecture
- Core Go application with GraphQL API using gqlgen
- Comprehensive data models for literary works, authors, translations
- Repository pattern with caching layer
- Authentication and authorization system
- Linguistics analysis capabilities with multiple adapters
- Vector search integration with Weaviate
- Docker containerization support
- Python data migration and analysis scripts
- Clean architecture with proper separation of concerns
- Production-ready configuration and middleware
- Proper .gitignore excluding vendor/, database files, and build artifacts
2025-08-13 07:42:32 +02:00

118 lines
3.2 KiB
Go

package main
import (
"context"
"net/http"
"os"
"os/signal"
"syscall"
"tercul/config"
"tercul/internal/app"
"tercul/logger"
"time"
"github.com/hibiken/asynq"
)
// main is the entry point for the Tercul application.
// It uses the ApplicationBuilder and ServerFactory to initialize all components
// and start the servers in a clean, maintainable way.
func main() {
// Load configuration from environment variables
config.LoadConfig()
// Initialize structured logger with appropriate log level
logger.SetDefaultLevel(logger.InfoLevel)
logger.LogInfo("Starting Tercul application",
logger.F("environment", config.Cfg.Environment),
logger.F("version", "1.0.0"))
// Build application components
appBuilder := app.NewApplicationBuilder()
if err := appBuilder.Build(); err != nil {
logger.LogFatal("Failed to build application",
logger.F("error", err))
}
defer appBuilder.Close()
// Create server factory
serverFactory := app.NewServerFactory(appBuilder)
// Create servers
graphQLServer, err := serverFactory.CreateGraphQLServer()
if err != nil {
logger.LogFatal("Failed to create GraphQL server",
logger.F("error", err))
}
backgroundServers, err := serverFactory.CreateBackgroundJobServers()
if err != nil {
logger.LogFatal("Failed to create background job servers",
logger.F("error", err))
}
playgroundServer := serverFactory.CreatePlaygroundServer()
// Start HTTP servers in goroutines
go func() {
logger.LogInfo("Starting GraphQL server",
logger.F("port", config.Cfg.ServerPort))
if err := graphQLServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
logger.LogFatal("Failed to start GraphQL server",
logger.F("error", err))
}
}()
go func() {
logger.LogInfo("Starting GraphQL playground",
logger.F("port", config.Cfg.PlaygroundPort))
if err := playgroundServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
logger.LogFatal("Failed to start GraphQL playground",
logger.F("error", err))
}
}()
// Start background job servers in goroutines
for i, server := range backgroundServers {
go func(serverIndex int, srv *asynq.Server) {
logger.LogInfo("Starting background job server",
logger.F("serverIndex", serverIndex))
if err := srv.Run(asynq.NewServeMux()); err != nil {
logger.LogError("Background job server failed",
logger.F("serverIndex", serverIndex),
logger.F("error", err))
}
}(i, server)
}
// Wait for interrupt signal to gracefully shutdown the servers
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
logger.LogInfo("Shutting down servers...")
// Graceful shutdown
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := graphQLServer.Shutdown(ctx); err != nil {
logger.LogError("GraphQL server forced to shutdown",
logger.F("error", err))
}
if err := playgroundServer.Shutdown(ctx); err != nil {
logger.LogError("GraphQL playground forced to shutdown",
logger.F("error", err))
}
// Shutdown background job servers
for i, server := range backgroundServers {
server.Shutdown()
logger.LogInfo("Background job server shutdown",
logger.F("serverIndex", i))
}
logger.LogInfo("All servers shutdown successfully")
}