diff --git a/internal/constant/constant.go b/internal/constant/constant.go index f305418..8f07961 100644 --- a/internal/constant/constant.go +++ b/internal/constant/constant.go @@ -123,7 +123,7 @@ const ( // Agent 状态 AgentStatusOnline = "online" AgentStatusOffline = "offline" - + // AppLog 分类 LogCategoryDefault = "default" LogCategorySystemNotice = "system_notice" @@ -149,6 +149,20 @@ const ( // TablePrefix 表前缀,从配置文件读取 var TablePrefix string +// Runtime 数据库配置快照,用于需要单独启动内部子进程(如 reposync)时显式透传数据库连接信息, +// 避免主进程启动阶段清理环境变量后,子进程意外回退到默认 sqlite 配置。 +var ( + RuntimeDBType string + RuntimeDBHost string + RuntimeDBPort int + RuntimeDBUser string + RuntimeDBPassword string + RuntimeDBName string + RuntimeDBPath string + RuntimeDBDSN string + RuntimeDBTablePrefix string +) + // Secret JWT和密码salt密钥,运行中自动从数据库加载 var Secret string diff --git a/internal/services/config_service.go b/internal/services/config_service.go index 1eb40d2..8ffe990 100644 --- a/internal/services/config_service.go +++ b/internal/services/config_service.go @@ -11,7 +11,7 @@ import ( ) type ServerConfig struct { - Port int `ini:"port"` + Port int `ini:"port"` Host string `ini:"host"` URLPrefix string `ini:"url_prefix"` PprofEnabled bool `ini:"pprof_enabled"` @@ -125,6 +125,15 @@ func LoadConfig(path string) (*AppConfig, error) { // 设置表前缀到 constant 包 constant.TablePrefix = Config.Database.TablePrefix + constant.RuntimeDBType = Config.Database.Type + constant.RuntimeDBHost = Config.Database.Host + constant.RuntimeDBPort = Config.Database.Port + constant.RuntimeDBUser = Config.Database.User + constant.RuntimeDBPassword = Config.Database.Password + constant.RuntimeDBName = Config.Database.DBName + constant.RuntimeDBPath = Config.Database.Path + constant.RuntimeDBDSN = Config.Database.DSN + constant.RuntimeDBTablePrefix = Config.Database.TablePrefix // 暂存旧的 Secret,不再直接给 constant 赋值(改为到 settings 初始化时判断) // constant.Secret = Config.Security.Secret diff --git a/internal/services/tasks/executor_service.go b/internal/services/tasks/executor_service.go index 98411ae..5b796e8 100644 --- a/internal/services/tasks/executor_service.go +++ b/internal/services/tasks/executor_service.go @@ -243,8 +243,6 @@ func (h *ServerSchedulerHandler) OnTaskCompleted(req *executor.ExecutionRequest, // 处理任务完成(更新统计、清理旧日志等) h.es.taskLogService.ProcessTaskCompletion(taskLog) - - // 更新内存缓冲 h.es.UpdateResult(*result) @@ -362,14 +360,14 @@ func (es *ExecutorService) HandleTaskRetry(task *models.Task, req *executor.Exec if task == nil { return } - + if !isSuccess || status == constant.TaskStatusFailed || status == constant.TaskStatusTimeout || exitCode != 0 { retryIndex := req.Metadata.RetryIndex if retryIndex < task.RetryCount { retryIndex++ logger.Infof("[Executor] 任务 #%s 执行失败/出错,将在 %d 秒后进行第 %d/%d 次重试...", task.ID, task.RetryInterval, retryIndex, task.RetryCount) - + es.scheduler.EnqueueDelayed(time.Duration(task.RetryInterval)*time.Second, func() *executor.ExecutionRequest { latestTask := es.taskService.GetTaskByID(task.ID) if latestTask == nil || !latestTask.Enabled { @@ -427,7 +425,7 @@ func (h *LocalTaskHooks) OnHeartbeat(ctx context.Context, logID string, duration // ExecuteDispatcher 实现任务分发逻辑 func (es *ExecutorService) ExecuteDispatcher(ctx context.Context, req *executor.ExecutionRequest, stdout, stderr io.Writer) (*executor.Result, error) { taskID := req.TaskID - + // 解析路径变量 (如 $SCRIPTS_DIR$) req.Command = es.ResolvePath(req.Command) req.WorkDir = es.ResolvePath(req.WorkDir) @@ -770,8 +768,8 @@ func (es *ExecutorService) CheckConcurrency(taskID string) error { if string(task.RunningGo) != "" { _ = json.Unmarshal([]byte(string(task.RunningGo)), &goids) } - - var config models.TaskConfig + + var config models.TaskConfig if string(task.Config) != "" { _ = json.Unmarshal([]byte(string(task.Config)), &config) } @@ -990,7 +988,7 @@ func (es *ExecutorService) BuildRepoCommand(task *models.Task) (string, string) if config.Extensions != "" { args = append(args, "--extensions", config.Extensions) } - + // 传递任务 ID,以便 reposync 内部直接处理脚本注册并输出日志 args = append(args, "--task-id", task.ID) args = append(args, "--task-timeout", fmt.Sprintf("%d", task.Timeout)) @@ -1005,7 +1003,7 @@ func (es *ExecutorService) BuildRepoCommand(task *models.Task) (string, string) } cmdStr := utils.QuotePath(exePath) + " " + strings.Join(quotedArgs, " ") - return buildRepoCommandEnvPrefix()+cmdStr, filepath.Dir(exePath) + return buildRepoCommandEnvPrefix() + cmdStr, filepath.Dir(exePath) } // loadEnvVars 加载环境变量和掩码信息,支持全局注入及重名合并 @@ -1083,7 +1081,35 @@ func buildRepoCommandEnvPrefix() string { } absScriptsDir := resolveAbsScriptsDir() - return "BH_CONFIG_PATH='" + strings.ReplaceAll(absConfig, "'", "'\\''") + "' BH_SCRIPTS_DIR='" + strings.ReplaceAll(absScriptsDir, "'", "'\\''") + "' " + parts := []string{ + shellEnvAssignment("BH_CONFIG_PATH", absConfig), + shellEnvAssignment("BH_SCRIPTS_DIR", absScriptsDir), + } + + appendIfSet := func(key string, value string) { + if strings.TrimSpace(value) == "" { + return + } + parts = append(parts, shellEnvAssignment(key, value)) + } + + appendIfSet("BH_DB_TYPE", constant.RuntimeDBType) + appendIfSet("BH_DB_HOST", constant.RuntimeDBHost) + if constant.RuntimeDBPort > 0 { + parts = append(parts, shellEnvAssignment("BH_DB_PORT", fmt.Sprintf("%d", constant.RuntimeDBPort))) + } + appendIfSet("BH_DB_USER", constant.RuntimeDBUser) + appendIfSet("BH_DB_PASSWORD", constant.RuntimeDBPassword) + appendIfSet("BH_DB_NAME", constant.RuntimeDBName) + appendIfSet("BH_DB_PATH", constant.RuntimeDBPath) + appendIfSet("BH_DB_DSN", constant.RuntimeDBDSN) + appendIfSet("BH_DB_TABLE_PREFIX", constant.RuntimeDBTablePrefix) + + return strings.Join(parts, " ") + " " +} + +func shellEnvAssignment(key, value string) string { + return key + "='" + strings.ReplaceAll(value, "'", "'\\''") + "'" } func resolveAbsScriptsDir() string {