311 lines
8.6 KiB
Go
311 lines
8.6 KiB
Go
package main
|
||
|
||
import (
|
||
"cmii-uav-watchdog-common/wdd_log"
|
||
"flag"
|
||
"os"
|
||
"os/exec"
|
||
"os/signal"
|
||
"strings"
|
||
"sync"
|
||
"syscall"
|
||
"time"
|
||
)
|
||
|
||
// 是否是Debug模式
|
||
var DebugMode = false
|
||
|
||
var (
|
||
businessProgramType = flag.String("business-program-type", "", "Type of business program (java or python)")
|
||
businessProgramPath = flag.String("business-program-path", "", "Path to the business program file")
|
||
stopRequested bool
|
||
currentCmd *exec.Cmd
|
||
mu sync.Mutex
|
||
)
|
||
|
||
// java 启动参数
|
||
var (
|
||
podName = "unknown"
|
||
imageName = "unknown"
|
||
imageVersion = "unknown"
|
||
workpath = "/cmii"
|
||
custJavaOpts = "-Xms200m -Xmx1500m -Djava.awt.headless=true -Dlog4j2.formatMsgNoLookups=true "
|
||
envJvmTimezone = "Asia/Shanghai"
|
||
k8sNamespace = "default"
|
||
applicationName = "app"
|
||
nacosRegistry = "helm-nacos:8848"
|
||
nacosDiscoveryIp = "127.0.0.1"
|
||
nacosDiscoveryPort = "8080"
|
||
nacosUsername = "nacos"
|
||
nacosPassword = "nacos"
|
||
bizConfigGroup = "wdd-biz"
|
||
sysConfigGroup = "wdd-sys"
|
||
)
|
||
|
||
// 初始化
|
||
func init() {
|
||
// 获取环境变量 特殊设置才能开启DEBUG
|
||
debugMode := os.Getenv("CMII_DEBUG_MODE")
|
||
if debugMode == "WDD_DEBUG" {
|
||
DebugMode = true
|
||
}
|
||
wdd_log.Info("DebugMode 是否开启: %v", DebugMode)
|
||
}
|
||
|
||
// 初始化配置并打印配置信息
|
||
func initConfig() {
|
||
// 获取环境变量
|
||
imageName = getEnvOrDefault("IMAGE_NAME", imageName)
|
||
if imageName != "unknown" {
|
||
parts := strings.Split(imageName, ":")
|
||
if len(parts) > 1 {
|
||
imageVersion = parts[len(parts)-1]
|
||
}
|
||
}
|
||
workpath = getEnvOrDefault("WORKPATH", workpath)
|
||
custJavaOpts = getEnvOrDefault("CUST_JAVA_OPTS", custJavaOpts)
|
||
envJvmTimezone = getEnvOrDefault("ENV_JVM_TIMEZONE", envJvmTimezone)
|
||
k8sNamespace = getEnvOrDefault("K8S_NAMESPACE", k8sNamespace)
|
||
applicationName = getEnvOrDefault("APPLICATION_NAME", applicationName)
|
||
nacosRegistry = getEnvOrDefault("NACOS_REGISTRY", nacosRegistry)
|
||
nacosDiscoveryIp = getEnvOrDefault("NACOS_DISCOVERY_IP", nacosDiscoveryIp)
|
||
nacosDiscoveryPort = getEnvOrDefault("NACOS_DISCOVERY_PORT", nacosDiscoveryPort)
|
||
nacosUsername = getEnvOrDefault("NACOS_USERNAME", nacosUsername)
|
||
nacosPassword = getEnvOrDefault("NACOS_PASSWORD", nacosPassword)
|
||
|
||
// 设置默认配置组
|
||
defaultConfigGroup := "default"
|
||
if imageVersion != "unknown" {
|
||
parts := strings.Split(imageVersion, "-")
|
||
if len(parts) > 0 {
|
||
defaultConfigGroup = parts[0]
|
||
}
|
||
}
|
||
|
||
bizConfigGroup = getEnvOrDefault("BIZ_CONFIG_GROUP", bizConfigGroup)
|
||
if bizConfigGroup == "" {
|
||
wdd_log.Info("[CONTAINER] As BIZ_CONFIG_GROUP is null, it set default value [%s]", defaultConfigGroup)
|
||
bizConfigGroup = defaultConfigGroup
|
||
os.Setenv("BIZ_CONFIG_GROUP", bizConfigGroup)
|
||
}
|
||
|
||
sysConfigGroup = getEnvOrDefault("SYS_CONFIG_GROUP", sysConfigGroup)
|
||
if sysConfigGroup == "" {
|
||
wdd_log.Info("[CONTAINER] As SYS_CONFIG_GROUP is null, it set default value [%s]", defaultConfigGroup)
|
||
sysConfigGroup = defaultConfigGroup
|
||
os.Setenv("SYS_CONFIG_GROUP", sysConfigGroup)
|
||
}
|
||
|
||
// 打印配置信息
|
||
wdd_log.Info("[CONTAINER] %s image is running ...", imageName)
|
||
wdd_log.Info("[CONTAINER] IMAGE_VERSION is %s", imageVersion)
|
||
wdd_log.Info("[CONTAINER] WORKPATH is %s", workpath)
|
||
wdd_log.Info("[CONTAINER] CUST_JAVA_OPTS is %s", custJavaOpts)
|
||
wdd_log.Info("[CONTAINER] JVM_TIMEZONE is %s", envJvmTimezone)
|
||
wdd_log.Info("[CONTAINER] K8S_NAMESPACE is %s", k8sNamespace)
|
||
wdd_log.Info("[CONTAINER] APPLICATION_NAME is %s", applicationName)
|
||
wdd_log.Info("[CONTAINER] NACOS_REGISTRY is %s", nacosRegistry)
|
||
wdd_log.Info("[CONTAINER] NACOS_DISCOVERY_IP is %s", nacosDiscoveryIp)
|
||
wdd_log.Info("[CONTAINER] NACOS_DISCOVERY_PORT is %s", nacosDiscoveryPort)
|
||
wdd_log.Info("[CONTAINER] NACOS_USERNAME is %s", nacosUsername)
|
||
wdd_log.Info("[CONTAINER] NACOS_PASSWORD is %s", nacosPassword)
|
||
wdd_log.Info("[CONTAINER] BIZ_CONFIG_GROUP is %s", bizConfigGroup)
|
||
wdd_log.Info("[CONTAINER] SYS_CONFIG_GROUP is %s", sysConfigGroup)
|
||
wdd_log.Info("[CONTAINER] starting...")
|
||
}
|
||
|
||
// 获取环境变量,如果为空则返回默认值
|
||
func getEnvOrDefault(key, defaultValue string) string {
|
||
value := os.Getenv(key)
|
||
if value == "" {
|
||
return defaultValue
|
||
}
|
||
return value
|
||
}
|
||
|
||
func startBusinessProcess(programType, programPath string) *exec.Cmd {
|
||
var cmd *exec.Cmd
|
||
switch programType {
|
||
case "java":
|
||
// 初始化配置
|
||
initConfig()
|
||
|
||
// 构建命令参数列表
|
||
args := []string{}
|
||
|
||
// 添加Java选项
|
||
if custJavaOpts != "" {
|
||
// 分割CUST_JAVA_OPTS中的多个参数
|
||
for _, opt := range splitArgs(custJavaOpts) {
|
||
if opt != "" {
|
||
args = append(args, opt)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 添加主JAR文件
|
||
args = append(args, "-jar", programPath)
|
||
|
||
// 添加其他参数
|
||
args = append(args, []string{
|
||
"--user.timezone=" + envJvmTimezone,
|
||
"-Dfile.encoding=UTF-8",
|
||
"--spring.main.allow-bean-definition-overriding=true",
|
||
"--spring.application.name=" + applicationName,
|
||
"--spring.cloud.nacos.username=" + nacosUsername,
|
||
"--spring.cloud.nacos.password=" + nacosPassword,
|
||
"--spring.cloud.nacos.config.server-addr=" + nacosRegistry,
|
||
"--spring.cloud.nacos.config.extension-configs[0].data-id=" + applicationName + ".yml",
|
||
"--spring.cloud.nacos.config.extension-configs[0].group=" + bizConfigGroup,
|
||
"--spring.cloud.nacos.config.extension-configs[0].refresh=true",
|
||
"--spring.cloud.nacos.config.shared-configs[0].data-id=cmii-backend-system.yml",
|
||
"--spring.cloud.nacos.config.shared-configs[0].group=" + sysConfigGroup,
|
||
"--spring.cloud.nacos.config.shared-configs[0].refresh=true",
|
||
"--spring.cloud.nacos.discovery.server-addr=" + nacosRegistry,
|
||
"--spring.cloud.nacos.discovery.ip=" + nacosDiscoveryIp,
|
||
"--spring.cloud.nacos.discovery.port=" + nacosDiscoveryPort,
|
||
}...)
|
||
|
||
wdd_log.Info("[CONTAINER] java args: %v", args)
|
||
|
||
cmd = exec.Command("java", args...)
|
||
case "python":
|
||
cmd = exec.Command("python", programPath)
|
||
default:
|
||
wdd_log.Error("不支持的业务程序类型: %s", programType)
|
||
}
|
||
return cmd
|
||
}
|
||
|
||
// 分割命令行参数
|
||
func splitArgs(s string) []string {
|
||
var args []string
|
||
var inQuote bool
|
||
var current string
|
||
var quoteChar rune
|
||
|
||
for _, r := range s {
|
||
switch {
|
||
case (r == '"' || r == '\'') && !inQuote:
|
||
inQuote = true
|
||
quoteChar = r
|
||
case r == quoteChar && inQuote:
|
||
inQuote = false
|
||
quoteChar = 0
|
||
case r == ' ' && !inQuote:
|
||
if current != "" {
|
||
args = append(args, current)
|
||
current = ""
|
||
}
|
||
default:
|
||
current += string(r)
|
||
}
|
||
}
|
||
|
||
if current != "" {
|
||
args = append(args, current)
|
||
}
|
||
|
||
return args
|
||
}
|
||
|
||
func main() {
|
||
// 解析命令行参数
|
||
flag.Parse()
|
||
if *businessProgramType == "" || *businessProgramPath == "" {
|
||
wdd_log.Error("缺少必要的参数: -business-program-type 和 -business-program-path 必须指定")
|
||
}
|
||
|
||
// 信号处理
|
||
signalChan := make(chan os.Signal, 1)
|
||
signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)
|
||
|
||
// StartHeartbeatDetection(signalChan)
|
||
|
||
go func() {
|
||
for sig := range signalChan {
|
||
wdd_log.Info("接收到信号: %v", sig)
|
||
mu.Lock()
|
||
stopRequested = true
|
||
if currentCmd != nil && currentCmd.Process != nil {
|
||
// 发送 SIGTERM 给业务进程
|
||
if err := currentCmd.Process.Signal(syscall.SIGTERM); err != nil {
|
||
wdd_log.Error("向进程发送SIGTERM信号失败: %v", err)
|
||
}
|
||
// 等待 10 秒后强制杀死进程
|
||
time.AfterFunc(10*time.Second, func() {
|
||
mu.Lock()
|
||
defer mu.Unlock()
|
||
if currentCmd != nil && currentCmd.Process != nil {
|
||
wdd_log.Warn("优雅关闭超时,发送SIGKILL信号")
|
||
currentCmd.Process.Kill()
|
||
}
|
||
})
|
||
}
|
||
mu.Unlock()
|
||
}
|
||
}()
|
||
|
||
// 授权检测
|
||
go func() {
|
||
for {
|
||
StartHeartbeatDetection(signalChan)
|
||
}
|
||
}()
|
||
|
||
// 主循环
|
||
for {
|
||
mu.Lock()
|
||
if stopRequested {
|
||
mu.Unlock()
|
||
wdd_log.Info("收到停止请求,正在关闭")
|
||
os.Exit(0)
|
||
}
|
||
mu.Unlock()
|
||
|
||
cmd := startBusinessProcess(*businessProgramType, *businessProgramPath)
|
||
cmd.Stdout = os.Stdout
|
||
cmd.Stderr = os.Stderr
|
||
|
||
// 启动业务进程
|
||
if err := cmd.Start(); err != nil {
|
||
wdd_log.Error("启动业务进程失败: %v", err)
|
||
time.Sleep(5 * time.Second)
|
||
continue
|
||
}
|
||
|
||
// 业务进程启动成功
|
||
if *businessProgramType == "java" {
|
||
wdd_log.Info("[CONTAINER] 程序启动成功!")
|
||
}
|
||
|
||
mu.Lock()
|
||
currentCmd = cmd
|
||
mu.Unlock()
|
||
|
||
// 等待业务进程退出
|
||
err := cmd.Wait()
|
||
mu.Lock()
|
||
currentCmd = nil
|
||
mu.Unlock()
|
||
|
||
if err != nil {
|
||
wdd_log.Error("业务进程异常退出: %v", err)
|
||
} else {
|
||
wdd_log.Info("业务进程正常退出")
|
||
}
|
||
|
||
mu.Lock()
|
||
if stopRequested {
|
||
mu.Unlock()
|
||
wdd_log.Info("收到停止请求,正在关闭")
|
||
os.Exit(0)
|
||
}
|
||
mu.Unlock()
|
||
|
||
// 等待 5 秒后重启
|
||
wdd_log.Info("5秒后重启业务进程...")
|
||
time.Sleep(5 * time.Second)
|
||
}
|
||
}
|