Skip to content

Commit 0ec1afa

Browse files
committed
fix timeout
1 parent e2c3619 commit 0ec1afa

File tree

4 files changed

+148
-71
lines changed

4 files changed

+148
-71
lines changed

backend/internal/api/configui.go

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -404,14 +404,16 @@ func (s *Server) handleGetConfig(c *gin.Context) {
404404
if len(cfg.ScheduledTasks) > 0 {
405405
resp.ScheduledTasks = make([]configUIScheduledTask, len(cfg.ScheduledTasks))
406406
for i, t := range cfg.ScheduledTasks {
407+
// 与调度执行、保存逻辑一致,避免旧配置无 product 时页面展示与后端实际不一致
408+
effectiveProduct := config.ResolveScheduledTaskProduct(t.Product, t.Project, t.Workspace, cfg.Global.Product)
407409
resp.ScheduledTasks[i] = configUIScheduledTask{
408410
Name: t.Name,
409411
Enabled: t.Enabled,
410412
Cron: t.Cron,
411413
Prompt: t.Prompt,
412414
EmployeeName: t.EmployeeName,
413415
ConciseReply: t.ConciseReply,
414-
Product: t.Product,
416+
Product: effectiveProduct,
415417
Project: t.Project,
416418
Workspace: t.Workspace,
417419
Region: t.Region,
@@ -630,14 +632,16 @@ func (s *Server) handleSaveConfig(c *gin.Context) {
630632
// 定时任务配置
631633
for _, t := range req.ScheduledTasks {
632634
if t.Name != "" || t.EmployeeName != "" || t.Webhook.URL != "" {
635+
// 与 Cron 调度、立即触发使用同一解析规则,保证落盘 product 与页面选择一致
636+
taskProduct := config.ResolveScheduledTaskProduct(t.Product, t.Project, t.Workspace, strings.TrimSpace(req.Global.Product))
633637
cfg.ScheduledTasks = append(cfg.ScheduledTasks, config.ScheduledTaskConfig{
634638
Name: t.Name,
635639
Enabled: t.Enabled,
636640
Cron: t.Cron,
637641
Prompt: t.Prompt,
638642
EmployeeName: t.EmployeeName,
639643
ConciseReply: t.ConciseReply,
640-
Product: t.Product,
644+
Product: taskProduct,
641645
Project: t.Project,
642646
Workspace: t.Workspace,
643647
Region: t.Region,
@@ -707,14 +711,18 @@ func (s *Server) handleTriggerTask(c *gin.Context) {
707711
clientCfg.Product = globalCfg.Global.Product
708712
}
709713

710-
// 确定任务使用的 product/project/workspace/region
711-
taskProduct := req.Product
712-
if taskProduct == "" {
713-
taskProduct = clientCfg.Product // 使用全局配置
714-
}
714+
// 与保存/Cron 使用同一 Resolve,保证与页面「对接产品」一致(仅 cms|sls)
715+
taskProduct := config.ResolveScheduledTaskProduct(req.Product, req.Project, req.Workspace, clientCfg.Product)
715716
taskProject := req.Project
716717
taskWorkspace := req.Workspace
717718
taskRegion := req.Region
719+
fullPrompt := req.Prompt
720+
if req.ConciseReply {
721+
fullPrompt += "\n\n简化最终输出 适合聊天工具上阅读"
722+
}
723+
promptLog := scheduler.PromptForLog(fullPrompt, 1200)
724+
log.Printf("[trigger-task] task=%q 使用 product=%q 问题=%s(原始 product=%q 全局=%q workspace=%q project=%q)",
725+
req.Name, taskProduct, promptLog, req.Product, clientCfg.Product, req.Workspace, req.Project)
718726

719727
type triggerResult struct {
720728
reply string
@@ -734,12 +742,12 @@ func (s *Server) handleTriggerTask(c *gin.Context) {
734742
select {
735743
case res := <-done:
736744
if res.err != nil {
737-
log.Printf("[Scheduler] 触发测试失败 task=%q: %v", req.Name, res.err)
745+
log.Printf("[Scheduler] 触发测试失败 task=%q product=%q 问题=%s employee=%q: %v", req.Name, taskProduct, promptLog, req.EmployeeName, res.err)
738746
c.JSON(http.StatusOK, gin.H{"ok": false, "error": res.err.Error()})
739747
return
740748
}
741-
log.Printf("[Scheduler] 触发测试完成 task=%q employee=%q 响应(%d 字): %s",
742-
req.Name, req.EmployeeName, len([]rune(res.reply)), res.reply)
749+
log.Printf("[Scheduler] 触发测试完成 task=%q product=%q 问题=%s employee=%q 响应(%d 字): %s",
750+
req.Name, taskProduct, promptLog, req.EmployeeName, len([]rune(res.reply)), res.reply)
743751

744752
// 如果填了 Webhook URL,顺便推送
745753
webhookSent := false
@@ -755,10 +763,10 @@ func (s *Server) handleTriggerTask(c *gin.Context) {
755763
webhookRaw = raw
756764
if err != nil {
757765
webhookErr = err.Error()
758-
log.Printf("[Scheduler] 触发测试 webhook 发送失败 task=%q: %v(平台响应: %s)", req.Name, err, raw)
766+
log.Printf("[Scheduler] 触发测试 webhook 发送失败 task=%q product=%q 问题=%s: %v(平台响应: %s)", req.Name, taskProduct, promptLog, err, raw)
759767
} else {
760768
webhookSent = true
761-
log.Printf("[Scheduler] 触发测试 webhook 发送成功 task=%q type=%s 平台响应: %s", req.Name, req.Webhook.Type, raw)
769+
log.Printf("[Scheduler] 触发测试 webhook 发送成功 task=%q product=%q 问题=%s type=%s 平台响应: %s", req.Name, taskProduct, promptLog, req.Webhook.Type, raw)
762770
}
763771
}
764772

@@ -770,8 +778,10 @@ func (s *Server) handleTriggerTask(c *gin.Context) {
770778
"webhookRaw": webhookRaw,
771779
})
772780

773-
case <-time.After(3 * time.Minute):
774-
c.JSON(http.StatusOK, gin.H{"ok": false, "error": "请求超时(3 分钟),数字员工响应过慢"})
781+
case <-time.After(31 * time.Minute):
782+
log.Printf("[trigger-task] task=%q product=%q 问题=%s employee=%q 请求超时(HTTP 等待 31m,与 SSE 30m 对齐)", req.Name, taskProduct, promptLog, req.EmployeeName)
783+
// 与 queryEmployee 内 SSE 的 30m 超时对齐,避免后台仍在跑但 HTTP 已提前返回
784+
c.JSON(http.StatusOK, gin.H{"ok": false, "error": "请求超时(30 分钟),数字员工响应过慢"})
775785
}
776786
}
777787

backend/internal/config/config.go

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"path/filepath"
99
"regexp"
1010
"strconv"
11+
"strings"
1112

1213
"gopkg.in/yaml.v3"
1314
)
@@ -46,8 +47,8 @@ type ScheduledTaskConfig struct {
4647
// 启用简洁输出:向 Prompt 末尾追加简化输出指令,适合 IM 场景
4748
ConciseReply bool `yaml:"conciseReply,omitempty"`
4849
// Product 指定该任务对接的数字员工所属产品:sls(默认)或 cms。
49-
// 为空时使用 global.product 的值
50-
Product string `yaml:"product,omitempty"`
50+
// 保存时始终规范为 sls/cms,与页面选择及调度执行一致(不使用 omitempty,避免落盘丢失)
51+
Product string `yaml:"product"`
5152
// Project 与 Workspace 根据产品类型二选一
5253
Project string `yaml:"project,omitempty"` // SLS 产品对应的 Project
5354
Workspace string `yaml:"workspace,omitempty"` // CMS 产品对应的 Workspace
@@ -748,6 +749,35 @@ func IsSlsProduct(product string) bool {
748749
return product == "" || product == "sls"
749750
}
750751

752+
// NormalizeScheduledTaskProduct 将表单/配置中的 product 规范为 cms 或 sls(大小写与空白容错)。
753+
func NormalizeScheduledTaskProduct(s string) string {
754+
s = strings.TrimSpace(strings.ToLower(s))
755+
if s == "cms" {
756+
return "cms"
757+
}
758+
return "sls"
759+
}
760+
761+
// ResolveScheduledTaskProduct 解析定时任务 / 手动触发测试 / 保存配置使用的 product,与页面下拉选项一致(仅 cms 或 sls)。
762+
// taskProduct 非空时以其为准并规范化;为空时:Workspace 非空则视为 cms,Project 非空则视为 sls,否则使用 globalProduct(再为空则默认 sls)。
763+
func ResolveScheduledTaskProduct(taskProduct, project, workspace, globalProduct string) string {
764+
p := strings.TrimSpace(taskProduct)
765+
if p != "" {
766+
return NormalizeScheduledTaskProduct(p)
767+
}
768+
if strings.TrimSpace(workspace) != "" {
769+
return "cms"
770+
}
771+
if strings.TrimSpace(project) != "" {
772+
return "sls"
773+
}
774+
g := strings.TrimSpace(globalProduct)
775+
if g != "" {
776+
return NormalizeScheduledTaskProduct(g)
777+
}
778+
return "sls"
779+
}
780+
751781
// GetProduct 获取对接产品类型(如果未配置则返回默认值 "sls")
752782
func (c *Config) GetProduct() string {
753783
if c.Global.Product == "" {

0 commit comments

Comments
 (0)