Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
139
cloud/maplefile-backend/app/app.go
Normal file
139
cloud/maplefile-backend/app/app.go
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/interface/http"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/interface/scheduler"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/interface/scheduler/tasks"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/storage/database/cassandradb"
|
||||
)
|
||||
|
||||
// Application represents the main application using Wire DI
|
||||
type Application struct {
|
||||
config *config.Config
|
||||
httpServer *http.WireServer
|
||||
logger *zap.Logger
|
||||
migrator *cassandradb.Migrator
|
||||
scheduler *scheduler.Scheduler
|
||||
ipAnonymizationTask *tasks.IPAnonymizationTask
|
||||
dbSession *gocql.Session
|
||||
}
|
||||
|
||||
// ProvideApplication creates the application instance for Wire
|
||||
func ProvideApplication(
|
||||
cfg *config.Config,
|
||||
httpServer *http.WireServer,
|
||||
logger *zap.Logger,
|
||||
migrator *cassandradb.Migrator,
|
||||
sched *scheduler.Scheduler,
|
||||
ipAnonymizationTask *tasks.IPAnonymizationTask,
|
||||
dbSession *gocql.Session,
|
||||
) *Application {
|
||||
return &Application{
|
||||
config: cfg,
|
||||
httpServer: httpServer,
|
||||
logger: logger,
|
||||
migrator: migrator,
|
||||
scheduler: sched,
|
||||
ipAnonymizationTask: ipAnonymizationTask,
|
||||
dbSession: dbSession,
|
||||
}
|
||||
}
|
||||
|
||||
// Start starts the application
|
||||
func (app *Application) Start() error {
|
||||
app.logger.Info("🚀 MapleFile Backend Starting (Wire DI)",
|
||||
zap.String("version", app.config.App.Version),
|
||||
zap.String("environment", app.config.App.Environment),
|
||||
zap.String("di_framework", "Google Wire"))
|
||||
|
||||
// Run database migrations automatically on startup if enabled
|
||||
if app.config.Database.AutoMigrate {
|
||||
app.logger.Info("Auto-migration enabled, running database migrations...")
|
||||
if err := app.migrator.Up(); err != nil {
|
||||
app.logger.Error("Failed to run database migrations", zap.Error(err))
|
||||
return fmt.Errorf("migration failed: %w", err)
|
||||
}
|
||||
app.logger.Info("✅ Database migrations completed successfully")
|
||||
|
||||
// Wait for schema agreement across all Cassandra nodes
|
||||
// This ensures all nodes have the new schema before we start accepting requests
|
||||
app.logger.Info("⏳ Waiting for Cassandra schema agreement...")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
if err := app.dbSession.AwaitSchemaAgreement(ctx); err != nil {
|
||||
app.logger.Warn("Schema agreement wait failed, continuing anyway",
|
||||
zap.Error(err),
|
||||
zap.String("note", "This may cause transient errors on first requests"))
|
||||
} else {
|
||||
app.logger.Info("✅ Cassandra schema agreement reached")
|
||||
}
|
||||
} else {
|
||||
app.logger.Info("Auto-migration disabled (DATABASE_AUTO_MIGRATE=false), skipping migrations")
|
||||
}
|
||||
|
||||
// Register scheduled tasks
|
||||
app.logger.Info("Registering scheduled tasks...")
|
||||
if err := app.scheduler.RegisterTask(app.ipAnonymizationTask); err != nil {
|
||||
app.logger.Error("Failed to register IP anonymization task", zap.Error(err))
|
||||
return fmt.Errorf("task registration failed: %w", err)
|
||||
}
|
||||
|
||||
// Start scheduler
|
||||
if err := app.scheduler.Start(); err != nil {
|
||||
app.logger.Error("Failed to start scheduler", zap.Error(err))
|
||||
return fmt.Errorf("scheduler startup failed: %w", err)
|
||||
}
|
||||
|
||||
// Start HTTP server in goroutine
|
||||
errChan := make(chan error, 1)
|
||||
go func() {
|
||||
if err := app.httpServer.Start(); err != nil {
|
||||
errChan <- err
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for interrupt signal or server error
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
select {
|
||||
case err := <-errChan:
|
||||
app.logger.Error("HTTP server failed", zap.Error(err))
|
||||
return fmt.Errorf("server startup failed: %w", err)
|
||||
case sig := <-quit:
|
||||
app.logger.Info("Received shutdown signal", zap.String("signal", sig.String()))
|
||||
}
|
||||
|
||||
app.logger.Info("👋 MapleFile Backend Shutting Down")
|
||||
|
||||
// Graceful shutdown with timeout
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Stop scheduler first
|
||||
app.logger.Info("Stopping scheduler...")
|
||||
if err := app.scheduler.Stop(); err != nil {
|
||||
app.logger.Error("Scheduler shutdown error", zap.Error(err))
|
||||
// Continue with shutdown even if scheduler fails
|
||||
}
|
||||
|
||||
// Stop HTTP server
|
||||
if err := app.httpServer.Shutdown(ctx); err != nil {
|
||||
app.logger.Error("Server shutdown error", zap.Error(err))
|
||||
return fmt.Errorf("server shutdown failed: %w", err)
|
||||
}
|
||||
|
||||
app.logger.Info("✅ MapleFile Backend Stopped Successfully")
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue