service/app/mix/cmd/main.go

250 lines
6.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"context"
"fmt"
"net"
"net/http"
"os"
"os/exec"
"os/signal"
"runtime"
"service/api/consts"
"service/app/mix/conf"
"service/app/mix/controller"
"service/app/mix/mediafiller"
"service/app/mix/service"
"service/library/apollo"
"service/library/configcenter"
"service/library/contentaudit/imageaudit"
"service/library/contentaudit/textaudit"
videomoderation "service/library/contentaudit/video_moderation"
"service/library/dingtalk"
"service/library/httpengine"
"service/library/logger"
"service/library/middleware"
"service/library/redis"
"service/library/servicediscovery"
"service/library/sms"
"service/library/validator"
"strings"
"syscall"
"time"
)
func main() {
defer func() {
logger.Recover()
}()
// 加载配置
// 1.默认配置
configPath := consts.ProductionConfigPath
//if os.Getenv("PROJECT_ENV") == "production" {
// configPath = consts.ProductionConfigPath
//}
cfg := new(conf.ConfigSt)
err := configcenter.LoadConfig(configPath, cfg)
if err != nil {
msg := fmt.Sprintf("LoadConfig fail, path: %v, err: %v", configPath, err)
PrintAndExit(msg)
}
// 初始化日志
logger.InitLogger(cfg.Log)
//初始化apollo
err = apollo.Init(cfg.Apollo)
if err != nil {
msg := fmt.Sprintf("Apollo init fail, path: %v, err: %v", configPath, err)
PrintAndExit(msg)
}
//初始化redis
err = redis.Init(cfg.RedisConfig)
if err != nil {
msg := fmt.Sprintf("Redis init fail, path: %v, err: %v", configPath, err)
PrintAndExit(msg)
}
// 初始化服务发现
err = servicediscovery.Init(cfg.SD)
if err != nil {
msg := fmt.Sprintf("Init servicediscovery fail, path: %v, err: %v", configPath, err)
PrintAndExit(msg)
}
// 初始化短信服务
err = sms.Init(cfg.Dysmsapi)
if err != nil {
msg := fmt.Sprintf("Sms init fail, path: %v, err: %v", configPath, err)
PrintAndExit(msg)
}
// 初始化钉钉机器人
dingtalk.InitDefaultDingTalkClient(cfg.DingTalkRobot)
// 初始化服务
service.DefaultService = service.NewService()
service.DefaultConfigService = service.NewConfigService()
service.DefaultCronService = service.NewCronService()
service.DefaultScriptsService = service.NewScriptsService()
service.DefaultImageAuditTaskResultHandler = service.NewImageAuditTaskResultHandler()
service.DefaultTextAuditTaskResultHandler = service.NewTextAuditTaskResultHandler()
service.DefaultVideoModerationTaskResultHandler = service.NewVideoModerationTaskResultHandler()
err = service.DefaultService.Init(cfg)
if err != nil {
msg := fmt.Sprintf("Service init fail, err: %v", err)
PrintAndExit(msg)
}
err = service.DefaultCronService.Init(cfg)
if err != nil {
msg := fmt.Sprintf("CronService init fail, err: %v", err)
PrintAndExit(msg)
}
// 连接到审核任务数据库接口
service.DefaultService.ConnectToImageAudit()
service.DefaultService.ConnectToTextAudit()
service.DefaultService.ConnectToVideoModeration()
//service.DefaultService.Run()
// 启动图像审核服务
imageaudit.Init(cfg.ImageAudit)
// 启动文字审核服务
textaudit.Init(cfg.TextAudit)
// 启动视频审核服务
videomoderation.Init(cfg.VideoModeration)
// 初始化媒体填充服务
mediafiller.Init(cfg.ServerInfo)
// 初始化http server
ip := GetIp()
port := cfg.App.Port
router := httpengine.NewRouter()
middleware.InitJwtAuthenticator(service.DefaultService.OpVerifyToken)
validator.InitDefaultNotNullValidator()
controller.Init(router)
srv := &http.Server{
Addr: fmt.Sprintf("%s:%d", ip, port),
Handler: router,
}
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
logger.Fatal("listen: %v", err)
return
}
}()
// 注册服务
go func() {
err := registerSD(ip, port)
if err != nil {
logger.Fatal("registerSD: %v", err)
return
}
setServerStatusFD(ServerStatusFDRun)
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
if err := servicediscovery.DeRegister(ip, port); err != nil {
logger.Fatal("DeRegister fail: %v", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
if err := srv.Shutdown(ctx); err != nil {
logger.Fatal("Server Shutdown:", err)
}
defer cancel()
select {
case <-ctx.Done():
logger.Info("timeout of 1 seconds.")
}
logger.Info("Server exited")
setServerStatusFD(ServerStatusFDStop)
}
func PrintAndExit(msg string) {
_, file, line, _ := runtime.Caller(1)
errorMsg := fmt.Sprintf("file %s, line %d, %s\n", file, line, msg)
_, _ = fmt.Fprintf(os.Stderr, errorMsg)
logger.Fatal(errorMsg)
time.Sleep(1) //wait logger flush
//os.Exit(1)
}
func GetIp() string {
addrs, err := net.InterfaceAddrs()
if err != nil {
PrintAndExit("get ip fail")
return "127.0.0.1"
}
retIp := ""
for _, address := range addrs {
// 检查ip地址判断是否回环地址
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
ip := ipnet.IP.String()
if strings.HasPrefix(ip, "172.") {
retIp = ip
break
}
}
}
}
return retIp
}
func registerSD(ip string, port int) error {
// 要等服务起来后再注册到consul否则会有问题
// 方法:调用 healthcheck
idx := 0
timer := time.NewTimer(time.Second * 5)
timerRetry := time.NewTicker(time.Second * 1)
for {
select {
case <-timer.C:
return fmt.Errorf("registerSD fail, ip: %v, port: %v", ip, port)
case <-timerRetry.C:
idx += 1
resp, err := http.Get(fmt.Sprintf("http://%s:%v/healthcheck", ip, port))
if err != nil {
logger.Error("healthcheck fail, err: %v", err)
continue
}
if resp.StatusCode == http.StatusOK {
if err := servicediscovery.Register(ip, port); err != nil {
logger.Error("registerSD fail, ip: %v, port: %v, err: %v", ip, port, err)
continue
}
return nil
}
}
}
}
func setServerStatusFD(status string) {
serverStatusFdPath := "/app/SERVER_STATUS_FD"
cmd := exec.Command("sh", "-c", fmt.Sprintf("echo %s > %s", status, serverStatusFdPath))
err := cmd.Run()
if err != nil {
logger.Info("run cmd fail, p: %v, err: %v", serverStatusFdPath, err)
return
}
logger.Info("SetServerStatusFD success: %v", status)
}
const (
ServerStatusFDRun = "RUN" // 服务运行中
ServerStatusFDStop = "STOP" // 服务停止
)