2026-01-29 16:54:00 +08:00
|
|
|
// entry function
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"errors"
|
|
|
|
|
"flag"
|
|
|
|
|
"fmt"
|
|
|
|
|
"log"
|
|
|
|
|
"net/http"
|
|
|
|
|
"os"
|
|
|
|
|
"os/signal"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"syscall"
|
2026-01-30 17:43:16 +08:00
|
|
|
"time"
|
2026-01-29 16:54:00 +08:00
|
|
|
|
|
|
|
|
"eventRT/config"
|
|
|
|
|
"eventRT/constants"
|
|
|
|
|
"eventRT/database"
|
|
|
|
|
"eventRT/logger"
|
|
|
|
|
"eventRT/mq"
|
|
|
|
|
"eventRT/util"
|
|
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
eventRTConfigDir = flag.String("eventRT_config_dir", "./configs", "config file dir")
|
|
|
|
|
eventRTConfigName = flag.String("eventRT_config_name", "config", "config file name")
|
|
|
|
|
eventRTConfigType = flag.String("eventRT_config_type", "yaml", "config file type")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
|
|
configPath := filepath.Join(*eventRTConfigDir, *eventRTConfigName+"."+*eventRTConfigType)
|
|
|
|
|
if _, err := os.Stat(configPath); os.IsNotExist(err) {
|
|
|
|
|
log.Println("configuration file not found,checking for example file")
|
|
|
|
|
|
|
|
|
|
exampleConfigPath := filepath.Join(*eventRTConfigDir, *eventRTConfigName+".example."+*eventRTConfigType)
|
|
|
|
|
configDir := filepath.Dir(configPath)
|
|
|
|
|
if err := os.MkdirAll(configDir, 0o755); err != nil {
|
|
|
|
|
panic(fmt.Errorf("failed to create config directory %s:%w", configDir, err))
|
|
|
|
|
}
|
|
|
|
|
if _, err := os.Stat(exampleConfigPath); err == nil {
|
|
|
|
|
if err := util.CopyFile(exampleConfigPath, configPath); err != nil {
|
|
|
|
|
panic(fmt.Errorf("failed to copy example config file:%w", err))
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
panic(errors.New("no config file and no config example file found"))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
eventRTConfig := config.ReadAndInitConfig(*eventRTConfigDir, *eventRTConfigName, *eventRTConfigType)
|
2026-01-30 17:43:16 +08:00
|
|
|
// init logger instance
|
2026-01-29 16:54:00 +08:00
|
|
|
logger.InitLoggerInstance(eventRTConfig.LoggerConfig)
|
|
|
|
|
|
2026-01-30 17:43:16 +08:00
|
|
|
// init MongoDB client
|
|
|
|
|
notifyCtx, stop := signal.NotifyContext(context.TODO(), os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
|
defer stop()
|
2026-01-29 16:54:00 +08:00
|
|
|
|
2026-01-30 17:43:16 +08:00
|
|
|
client := database.InitMongoInstance(notifyCtx, eventRTConfig)
|
|
|
|
|
defer func() {
|
|
|
|
|
disconnectCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
|
|
defer cancel()
|
|
|
|
|
if err := client.Disconnect(disconnectCtx); err != nil {
|
|
|
|
|
logger.Error(notifyCtx, "mongodb disconnect failed", "err", err)
|
|
|
|
|
} else {
|
|
|
|
|
logger.Info(notifyCtx, "mongodb connection closed gracefully")
|
|
|
|
|
}
|
|
|
|
|
}()
|
2026-01-29 16:54:00 +08:00
|
|
|
|
2026-01-30 17:43:16 +08:00
|
|
|
// init RabbitMQ connection
|
|
|
|
|
mq.InitRabbitProxy(notifyCtx, eventRTConfig.RabbitMQConfig)
|
|
|
|
|
defer mq.GetConn().Close()
|
2026-01-29 16:54:00 +08:00
|
|
|
|
|
|
|
|
// use release mode in production
|
|
|
|
|
if eventRTConfig.DeployEnv == constants.ProductionDeployMode {
|
|
|
|
|
gin.SetMode(gin.ReleaseMode)
|
|
|
|
|
}
|
|
|
|
|
engine := gin.New()
|
|
|
|
|
engine.Use(gin.Logger(), gin.Recovery())
|
|
|
|
|
|
|
|
|
|
// TODO k8s liveness & readiness probe endpoints
|
|
|
|
|
// engine.GET("/ping", func(c *gin.Context) {
|
|
|
|
|
// c.JSON(200, gin.H{"status": "ok"})
|
|
|
|
|
// })
|
|
|
|
|
|
|
|
|
|
server := http.Server{
|
|
|
|
|
Addr: eventRTConfig.ServiceAddr,
|
|
|
|
|
Handler: engine,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
go func() {
|
2026-01-30 17:43:16 +08:00
|
|
|
<-notifyCtx.Done()
|
2026-02-06 17:55:30 +08:00
|
|
|
ctx := context.Background()
|
|
|
|
|
logger.Info(ctx, "shutdown signal received, cleaning up...")
|
|
|
|
|
shutdownCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
2026-01-30 17:43:16 +08:00
|
|
|
defer cancel()
|
|
|
|
|
if err := server.Shutdown(shutdownCtx); err != nil {
|
|
|
|
|
logger.Error(shutdownCtx, "server shutdown failed", "err", err)
|
2026-01-29 16:54:00 +08:00
|
|
|
}
|
2026-02-06 17:55:30 +08:00
|
|
|
mq.CloseRabbitProxy()
|
|
|
|
|
logger.Info(ctx, "resources cleaned up, exiting")
|
2026-01-29 16:54:00 +08:00
|
|
|
}()
|
|
|
|
|
|
2026-01-30 17:43:16 +08:00
|
|
|
logger.Info(notifyCtx, "starting EventRT server")
|
2026-01-29 16:54:00 +08:00
|
|
|
err := server.ListenAndServe()
|
|
|
|
|
if err != nil {
|
|
|
|
|
if err == http.ErrServerClosed {
|
|
|
|
|
// the service receives the shutdown signal normally and then closes
|
2026-01-30 17:43:16 +08:00
|
|
|
logger.Info(notifyCtx, "server closed under request")
|
2026-01-29 16:54:00 +08:00
|
|
|
} else {
|
|
|
|
|
// abnormal shutdown of service
|
2026-01-30 17:43:16 +08:00
|
|
|
logger.Error(notifyCtx, "server closed unexpected", "err", err)
|
2026-01-29 16:54:00 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|