feat: add random delay
This commit is contained in:
+9
-3
@@ -51,8 +51,9 @@ type AgentTask struct {
|
|||||||
Timeout int `json:"timeout"`
|
Timeout int `json:"timeout"`
|
||||||
WorkDir string `json:"work_dir"`
|
WorkDir string `json:"work_dir"`
|
||||||
Envs string `json:"envs"`
|
Envs string `json:"envs"`
|
||||||
Languages []map[string]string `json:"languages"`
|
Languages []map[string]string `json:"languages"`
|
||||||
Enabled bool `json:"enabled"`
|
RandomRange int `json:"random_range"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *AgentTask) GetID() string {
|
func (t *AgentTask) GetID() string {
|
||||||
@@ -98,6 +99,10 @@ func (t *AgentTask) GetSchedule() string {
|
|||||||
return t.Cron
|
return t.Cron
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *AgentTask) GetRandomRange() int {
|
||||||
|
return t.RandomRange
|
||||||
|
}
|
||||||
|
|
||||||
type TaskResult struct {
|
type TaskResult struct {
|
||||||
TaskID uint `json:"task_id"`
|
TaskID uint `json:"task_id"`
|
||||||
LogID uint `json:"log_id"`
|
LogID uint `json:"log_id"`
|
||||||
@@ -674,7 +679,8 @@ func (a *Agent) updateTasks(tasks []AgentTask) {
|
|||||||
oldTask, exists := a.tasks[id]
|
oldTask, exists := a.tasks[id]
|
||||||
if !exists || oldTask.Schedule != task.Schedule || oldTask.Command != task.Command ||
|
if !exists || oldTask.Schedule != task.Schedule || oldTask.Command != task.Command ||
|
||||||
oldTask.Enabled != task.Enabled || oldTask.Timeout != task.Timeout ||
|
oldTask.Enabled != task.Enabled || oldTask.Timeout != task.Timeout ||
|
||||||
oldTask.WorkDir != task.WorkDir || oldTask.Envs != task.Envs {
|
oldTask.WorkDir != task.WorkDir || oldTask.Envs != task.Envs ||
|
||||||
|
oldTask.RandomRange != task.RandomRange {
|
||||||
if task.Enabled {
|
if task.Enabled {
|
||||||
err := a.cronManager.AddTask(task)
|
err := a.cronManager.AddTask(task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ func (tc *TaskController) CreateTask(c *gin.Context) {
|
|||||||
TriggerType string `json:"trigger_type"`
|
TriggerType string `json:"trigger_type"`
|
||||||
RetryCount int `json:"retry_count"`
|
RetryCount int `json:"retry_count"`
|
||||||
RetryInterval int `json:"retry_interval"`
|
RetryInterval int `json:"retry_interval"`
|
||||||
|
RandomRange int `json:"random_range"`
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
@@ -93,7 +94,7 @@ func (tc *TaskController) CreateTask(c *gin.Context) {
|
|||||||
workDir = resolveWorkDir(req.WorkDir)
|
workDir = resolveWorkDir(req.WorkDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
task := tc.taskService.CreateTask(req.Name, req.Command, req.Schedule, req.Timeout, workDir, req.CleanConfig, req.Envs, req.Type, req.Config, req.AgentID, req.Languages, req.TriggerType, req.Tags, req.RetryCount, req.RetryInterval)
|
task := tc.taskService.CreateTask(req.Name, req.Command, req.Schedule, req.Timeout, workDir, req.CleanConfig, req.Envs, req.Type, req.Config, req.AgentID, req.Languages, req.TriggerType, req.Tags, req.RetryCount, req.RetryInterval, req.RandomRange)
|
||||||
|
|
||||||
// 如果是 Agent 任务,通知 Agent;否则添加到本地 cron
|
// 如果是 Agent 任务,通知 Agent;否则添加到本地 cron
|
||||||
if task.AgentID != nil && *task.AgentID > 0 {
|
if task.AgentID != nil && *task.AgentID > 0 {
|
||||||
@@ -172,6 +173,7 @@ func (tc *TaskController) UpdateTask(c *gin.Context) {
|
|||||||
TriggerType string `json:"trigger_type"`
|
TriggerType string `json:"trigger_type"`
|
||||||
RetryCount int `json:"retry_count"`
|
RetryCount int `json:"retry_count"`
|
||||||
RetryInterval int `json:"retry_interval"`
|
RetryInterval int `json:"retry_interval"`
|
||||||
|
RandomRange int `json:"random_range"`
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
@@ -192,7 +194,7 @@ func (tc *TaskController) UpdateTask(c *gin.Context) {
|
|||||||
workDir = resolveWorkDir(req.WorkDir)
|
workDir = resolveWorkDir(req.WorkDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
task := tc.taskService.UpdateTask(id, req.Name, req.Command, req.Schedule, req.Timeout, workDir, req.CleanConfig, req.Envs, req.Enabled, req.Type, req.Config, req.AgentID, req.Languages, req.TriggerType, req.Tags, req.RetryCount, req.RetryInterval)
|
task := tc.taskService.UpdateTask(id, req.Name, req.Command, req.Schedule, req.Timeout, workDir, req.CleanConfig, req.Envs, req.Enabled, req.Type, req.Config, req.AgentID, req.Languages, req.TriggerType, req.Tags, req.RetryCount, req.RetryInterval, req.RandomRange)
|
||||||
if task == nil {
|
if task == nil {
|
||||||
utils.NotFound(c, "任务不存在")
|
utils.NotFound(c, "任务不存在")
|
||||||
return
|
return
|
||||||
|
|||||||
+30
-15
@@ -1,7 +1,9 @@
|
|||||||
package executor
|
package executor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/rand"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/engigu/baihu-panel/internal/systime"
|
"github.com/engigu/baihu-panel/internal/systime"
|
||||||
|
|
||||||
@@ -87,27 +89,40 @@ func (m *CronManager) AddTask(task CronTask) error {
|
|||||||
m.logger.Errorf("[CronManager] 任务 #%s 执行过程中发生 Panic: %v", taskID, r)
|
m.logger.Errorf("[CronManager] 任务 #%s 执行过程中发生 Panic: %v", taskID, r)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
m.logger.Infof("[CronManager] 触发计划任务 #%s (%s)", taskID, name)
|
|
||||||
|
|
||||||
req := &ExecutionRequest{
|
// 构造执行请求的 Builder
|
||||||
TaskID: taskID,
|
reqBuilder := func() *ExecutionRequest {
|
||||||
Name: name,
|
return &ExecutionRequest{
|
||||||
Command: cmd,
|
TaskID: taskID,
|
||||||
Type: TaskTypeCron,
|
Name: name,
|
||||||
Timeout: timeout,
|
Command: cmd,
|
||||||
WorkDir: workDir,
|
Type: TaskTypeCron,
|
||||||
Envs: ParseEnvVars(envs),
|
Timeout: timeout,
|
||||||
Languages: languages,
|
WorkDir: workDir,
|
||||||
UseMise: useMise,
|
Envs: ParseEnvVars(envs),
|
||||||
|
Languages: languages,
|
||||||
|
UseMise: useMise,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果有关联的 Scheduler,加入队列执行
|
randomRange := task.GetRandomRange()
|
||||||
if m.scheduler != nil {
|
if randomRange > 0 && m.scheduler != nil {
|
||||||
m.scheduler.EnqueueOrExecute(req)
|
// 生成 0 到 randomRange 之间的随机秒数
|
||||||
|
delaySeconds := rand.Intn(randomRange)
|
||||||
|
delay := time.Duration(delaySeconds) * time.Second
|
||||||
|
m.logger.Infof("[CronManager] 任务 #%s 将随机延迟 %v (范围: %ds) 后入队执行", taskID, delay, randomRange)
|
||||||
|
|
||||||
|
// 使用调度器的延时投递功能,不阻塞当前 Cron 协程
|
||||||
|
m.scheduler.EnqueueDelayed(delay, reqBuilder)
|
||||||
|
} else {
|
||||||
|
m.logger.Infof("[CronManager] 触发计划任务 #%s (%s)", taskID, name)
|
||||||
|
if m.scheduler != nil {
|
||||||
|
m.scheduler.EnqueueOrExecute(reqBuilder())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 触发下次运行时间更新事件
|
// 触发下次运行时间更新事件
|
||||||
m.triggerNextRunEvent(taskID, req)
|
m.triggerNextRunEvent(taskID, &ExecutionRequest{TaskID: taskID})
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ type CronTask interface {
|
|||||||
Task
|
Task
|
||||||
GetSchedule() string
|
GetSchedule() string
|
||||||
UseMise() bool
|
UseMise() bool
|
||||||
|
GetRandomRange() int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request 任务执行请求
|
// Request 任务执行请求
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/engigu/baihu-panel/internal/constant"
|
"github.com/engigu/baihu-panel/internal/constant"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@@ -59,8 +61,29 @@ type AgentTask struct {
|
|||||||
Timeout int `json:"timeout"`
|
Timeout int `json:"timeout"`
|
||||||
WorkDir string `json:"work_dir"`
|
WorkDir string `json:"work_dir"`
|
||||||
Envs string `json:"envs"`
|
Envs string `json:"envs"`
|
||||||
Languages []map[string]string `json:"languages"`
|
Languages []map[string]string `json:"languages"`
|
||||||
Enabled bool `json:"enabled"`
|
RandomRange int `json:"random_range"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t AgentTask) GetID() string {
|
||||||
|
return strconv.FormatUint(uint64(t.ID), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t AgentTask) GetName() string {
|
||||||
|
return t.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t AgentTask) GetCommand() string {
|
||||||
|
return t.Command
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t AgentTask) GetSchedule() string {
|
||||||
|
return t.Schedule
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t AgentTask) GetRandomRange() int {
|
||||||
|
return t.RandomRange
|
||||||
}
|
}
|
||||||
|
|
||||||
// AgentTaskResult Agent 上报的任务执行结果
|
// AgentTaskResult Agent 上报的任务执行结果
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ type Task struct {
|
|||||||
AgentID *uint `json:"agent_id" gorm:"index"` // Agent ID,为空表示本地执行
|
AgentID *uint `json:"agent_id" gorm:"index"` // Agent ID,为空表示本地执行
|
||||||
RetryCount int `json:"retry_count" gorm:"default:0"` // 失败重试次数
|
RetryCount int `json:"retry_count" gorm:"default:0"` // 失败重试次数
|
||||||
RetryInterval int `json:"retry_interval" gorm:"default:0"` // 失败重试间隔(秒)
|
RetryInterval int `json:"retry_interval" gorm:"default:0"` // 失败重试间隔(秒)
|
||||||
|
RandomRange int `json:"random_range" gorm:"default:0"` // 随机延迟范围(秒)
|
||||||
Enabled bool `json:"enabled" gorm:"default:true"`
|
Enabled bool `json:"enabled" gorm:"default:true"`
|
||||||
RunningGo string `json:"running_go" gorm:"type:text"` // 正在运行的 go routine id 数组 (JSON)
|
RunningGo string `json:"running_go" gorm:"type:text"` // 正在运行的 go routine id 数组 (JSON)
|
||||||
LastRun *LocalTime `json:"last_run"`
|
LastRun *LocalTime `json:"last_run"`
|
||||||
@@ -103,6 +104,10 @@ func (t *Task) GetSchedule() string {
|
|||||||
return t.Schedule
|
return t.Schedule
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Task) GetRandomRange() int {
|
||||||
|
return t.RandomRange
|
||||||
|
}
|
||||||
|
|
||||||
// TaskLog 代表任务执行的日志记录
|
// TaskLog 代表任务执行的日志记录
|
||||||
type TaskLog struct {
|
type TaskLog struct {
|
||||||
ID uint `json:"id" gorm:"primaryKey"`
|
ID uint `json:"id" gorm:"primaryKey"`
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ type TaskVO struct {
|
|||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
RetryCount int `json:"retry_count"`
|
RetryCount int `json:"retry_count"`
|
||||||
RetryInterval int `json:"retry_interval"`
|
RetryInterval int `json:"retry_interval"`
|
||||||
|
RandomRange int `json:"random_range"`
|
||||||
LastRun *models.LocalTime `json:"last_run"`
|
LastRun *models.LocalTime `json:"last_run"`
|
||||||
NextRun *models.LocalTime `json:"next_run"`
|
NextRun *models.LocalTime `json:"next_run"`
|
||||||
CreatedAt models.LocalTime `json:"created_at"`
|
CreatedAt models.LocalTime `json:"created_at"`
|
||||||
@@ -53,6 +54,7 @@ func ToTaskVO(task *models.Task) *TaskVO {
|
|||||||
Enabled: task.Enabled,
|
Enabled: task.Enabled,
|
||||||
RetryCount: task.RetryCount,
|
RetryCount: task.RetryCount,
|
||||||
RetryInterval: task.RetryInterval,
|
RetryInterval: task.RetryInterval,
|
||||||
|
RandomRange: task.RandomRange,
|
||||||
LastRun: task.LastRun,
|
LastRun: task.LastRun,
|
||||||
NextRun: task.NextRun,
|
NextRun: task.NextRun,
|
||||||
CreatedAt: task.CreatedAt,
|
CreatedAt: task.CreatedAt,
|
||||||
|
|||||||
@@ -317,9 +317,10 @@ func (s *AgentService) GetTasks(agentID uint) []models.AgentTask {
|
|||||||
Schedule: task.Schedule,
|
Schedule: task.Schedule,
|
||||||
Timeout: task.Timeout,
|
Timeout: task.Timeout,
|
||||||
WorkDir: task.WorkDir,
|
WorkDir: task.WorkDir,
|
||||||
Envs: envVarsStr, // 传递 "KEY1=VALUE1,KEY2=VALUE2" 格式
|
Envs: envVarsStr, // 传递 "KEY1=VALUE1,KEY2=VALUE2" 格式
|
||||||
Languages: task.Languages,
|
Languages: task.Languages,
|
||||||
Enabled: task.Enabled,
|
RandomRange: task.RandomRange,
|
||||||
|
Enabled: task.Enabled,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ func NewTaskService() *TaskService {
|
|||||||
return &TaskService{}
|
return &TaskService{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *TaskService) CreateTask(name, command, schedule string, timeout int, workDir, cleanConfig, envs, taskType, config string, agentID *uint, languages []map[string]string, triggerType string, tags string, retryCount int, retryInterval int) *models.Task {
|
func (ts *TaskService) CreateTask(name, command, schedule string, timeout int, workDir, cleanConfig, envs, taskType, config string, agentID *uint, languages []map[string]string, triggerType string, tags string, retryCount int, retryInterval int, randomRange int) *models.Task {
|
||||||
if taskType == "" {
|
if taskType == "" {
|
||||||
taskType = "task"
|
taskType = "task"
|
||||||
}
|
}
|
||||||
@@ -36,6 +36,7 @@ func (ts *TaskService) CreateTask(name, command, schedule string, timeout int, w
|
|||||||
Enabled: true,
|
Enabled: true,
|
||||||
RetryCount: retryCount,
|
RetryCount: retryCount,
|
||||||
RetryInterval: retryInterval,
|
RetryInterval: retryInterval,
|
||||||
|
RandomRange: randomRange,
|
||||||
}
|
}
|
||||||
if triggerType != constant.TriggerTypeCron {
|
if triggerType != constant.TriggerTypeCron {
|
||||||
task.NextRun = nil
|
task.NextRun = nil
|
||||||
@@ -83,7 +84,7 @@ func (ts *TaskService) GetTaskByID(id int) *models.Task {
|
|||||||
return &task
|
return &task
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *TaskService) UpdateTask(id int, name, command, schedule string, timeout int, workDir, cleanConfig, envs string, enabled bool, taskType, config string, agentID *uint, languages []map[string]string, triggerType string, tags string, retryCount int, retryInterval int) *models.Task {
|
func (ts *TaskService) UpdateTask(id int, name, command, schedule string, timeout int, workDir, cleanConfig, envs string, enabled bool, taskType, config string, agentID *uint, languages []map[string]string, triggerType string, tags string, retryCount int, retryInterval int, randomRange int) *models.Task {
|
||||||
var task models.Task
|
var task models.Task
|
||||||
if err := database.DB.First(&task, id).Error; err != nil {
|
if err := database.DB.First(&task, id).Error; err != nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -101,6 +102,7 @@ func (ts *TaskService) UpdateTask(id int, name, command, schedule string, timeou
|
|||||||
task.Languages = languages
|
task.Languages = languages
|
||||||
task.RetryCount = retryCount
|
task.RetryCount = retryCount
|
||||||
task.RetryInterval = retryInterval
|
task.RetryInterval = retryInterval
|
||||||
|
task.RandomRange = randomRange
|
||||||
if taskType != "" {
|
if taskType != "" {
|
||||||
task.Type = taskType
|
task.Type = taskType
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -286,6 +286,7 @@ export interface Task {
|
|||||||
envs: string
|
envs: string
|
||||||
retry_count: number
|
retry_count: number
|
||||||
retry_interval: number
|
retry_interval: number
|
||||||
|
random_range: number
|
||||||
languages: { name: string; version: string }[]
|
languages: { name: string; version: string }[]
|
||||||
agent_id: number | null
|
agent_id: number | null
|
||||||
enabled: boolean
|
enabled: boolean
|
||||||
|
|||||||
@@ -327,10 +327,19 @@ async function save() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-4 items-center gap-2 sm:gap-3">
|
<div class="grid grid-cols-1 sm:grid-cols-4 items-center gap-2 sm:gap-3">
|
||||||
<Label class="sm:text-right text-sm">超时/清理</Label>
|
<Label class="sm:text-right text-sm">随机延迟</Label>
|
||||||
|
<div class="sm:col-span-3 flex items-center gap-2">
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<Input v-model.number="form.random_range" type="number" :min="0" :step="1" @input="form.random_range = Math.max(0, Math.floor(form.random_range || 0))" placeholder="0" class="w-20 h-9 text-sm" />
|
||||||
|
<span class="text-sm text-muted-foreground whitespace-nowrap">秒</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-4 items-center gap-2 sm:gap-3">
|
||||||
|
<Label class="sm:text-right text-sm">超时清理</Label>
|
||||||
<div class="sm:col-span-3 flex flex-wrap items-center gap-2">
|
<div class="sm:col-span-3 flex flex-wrap items-center gap-2">
|
||||||
<div class="flex items-center gap-1.5">
|
<div class="flex items-center gap-1.5">
|
||||||
<Input v-model.number="form.timeout" type="number" placeholder="30" class="w-20 h-9 text-sm" />
|
<Input v-model.number="form.timeout" type="number" :min="0" :step="1" @input="form.timeout = Math.max(0, Math.floor(form.timeout || 0))" placeholder="30" class="w-20 h-9 text-sm" />
|
||||||
<span class="text-sm text-muted-foreground whitespace-nowrap">分钟</span>
|
<span class="text-sm text-muted-foreground whitespace-nowrap">分钟</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-1.5">
|
<div class="flex items-center gap-1.5">
|
||||||
@@ -353,12 +362,12 @@ async function save() {
|
|||||||
<Label class="sm:text-right text-sm">失败重试</Label>
|
<Label class="sm:text-right text-sm">失败重试</Label>
|
||||||
<div class="sm:col-span-3 flex items-center gap-2">
|
<div class="sm:col-span-3 flex items-center gap-2">
|
||||||
<div class="flex items-center gap-1.5">
|
<div class="flex items-center gap-1.5">
|
||||||
<Input v-model.number="form.retry_count" type="number" placeholder="0" class="w-16 h-9 text-sm" />
|
<Input v-model.number="form.retry_count" type="number" :min="0" :step="1" @input="form.retry_count = Math.max(0, Math.floor(form.retry_count || 0))" placeholder="0" class="w-16 h-9 text-sm" />
|
||||||
<span class="text-sm text-muted-foreground whitespace-nowrap">次</span>
|
<span class="text-sm text-muted-foreground whitespace-nowrap">次</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-1.5 ml-2" v-if="form.retry_count && form.retry_count > 0">
|
<div class="flex items-center gap-1.5 ml-2" v-if="form.retry_count && form.retry_count > 0">
|
||||||
<span class="text-sm text-muted-foreground whitespace-nowrap">间隔</span>
|
<span class="text-sm text-muted-foreground whitespace-nowrap">间隔</span>
|
||||||
<Input v-model.number="form.retry_interval" type="number" placeholder="0" class="w-16 h-9 text-sm" />
|
<Input v-model.number="form.retry_interval" type="number" :min="0" :step="1" @input="form.retry_interval = Math.max(0, Math.floor(form.retry_interval || 0))" placeholder="0" class="w-16 h-9 text-sm" />
|
||||||
<span class="text-sm text-muted-foreground whitespace-nowrap">秒</span>
|
<span class="text-sm text-muted-foreground whitespace-nowrap">秒</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -572,11 +572,21 @@ async function save() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-4 items-center gap-2 sm:gap-3" v-if="selectedTriggerType === TRIGGER_TYPE.CRON">
|
||||||
|
<Label class="sm:text-right text-sm">随机延迟</Label>
|
||||||
|
<div class="sm:col-span-3 flex items-center gap-2">
|
||||||
|
<div class="flex items-center gap-1.5">
|
||||||
|
<Input v-model.number="form.random_range" type="number" :min="0" :step="1" @input="form.random_range = Math.max(0, Math.floor(form.random_range || 0))" placeholder="0" class="w-20 h-9 text-sm" />
|
||||||
|
<span class="text-sm text-muted-foreground whitespace-nowrap">秒</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-[11px] text-muted-foreground ml-1">开启后,任务将在定时时间点后的 0 ~ {{ form.random_range || 0 }} 秒内随机执行。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-4 items-center gap-2 sm:gap-3">
|
<div class="grid grid-cols-1 sm:grid-cols-4 items-center gap-2 sm:gap-3">
|
||||||
<Label class="sm:text-right text-sm">超时/清理</Label>
|
<Label class="sm:text-right text-sm">超时清理</Label>
|
||||||
<div class="sm:col-span-3 flex flex-wrap items-center gap-2">
|
<div class="sm:col-span-3 flex flex-wrap items-center gap-2">
|
||||||
<div class="flex items-center gap-1.5">
|
<div class="flex items-center gap-1.5">
|
||||||
<Input v-model.number="form.timeout" type="number" placeholder="30" class="w-20 h-9 text-sm" />
|
<Input v-model.number="form.timeout" type="number" :min="0" :step="1" @input="form.timeout = Math.max(0, Math.floor(form.timeout || 0))" placeholder="30" class="w-20 h-9 text-sm" />
|
||||||
<span class="text-sm text-muted-foreground whitespace-nowrap">分钟</span>
|
<span class="text-sm text-muted-foreground whitespace-nowrap">分钟</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-1.5">
|
<div class="flex items-center gap-1.5">
|
||||||
@@ -609,12 +619,12 @@ async function save() {
|
|||||||
<Label class="sm:text-right text-sm">失败重试</Label>
|
<Label class="sm:text-right text-sm">失败重试</Label>
|
||||||
<div class="sm:col-span-3 flex items-center gap-2">
|
<div class="sm:col-span-3 flex items-center gap-2">
|
||||||
<div class="flex items-center gap-1.5">
|
<div class="flex items-center gap-1.5">
|
||||||
<Input v-model.number="form.retry_count" type="number" placeholder="0" class="w-16 h-9 text-sm" />
|
<Input v-model.number="form.retry_count" type="number" :min="0" :step="1" @input="form.retry_count = Math.max(0, Math.floor(form.retry_count || 0))" placeholder="0" class="w-16 h-9 text-sm" />
|
||||||
<span class="text-sm text-muted-foreground whitespace-nowrap">次</span>
|
<span class="text-sm text-muted-foreground whitespace-nowrap">次</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-1.5 ml-2" v-if="form.retry_count && form.retry_count > 0">
|
<div class="flex items-center gap-1.5 ml-2" v-if="form.retry_count && form.retry_count > 0">
|
||||||
<span class="text-sm text-muted-foreground whitespace-nowrap">间隔</span>
|
<span class="text-sm text-muted-foreground whitespace-nowrap">间隔</span>
|
||||||
<Input v-model.number="form.retry_interval" type="number" placeholder="0" class="w-16 h-9 text-sm" />
|
<Input v-model.number="form.retry_interval" type="number" :min="0" :step="1" @input="form.retry_interval = Math.max(0, Math.floor(form.retry_interval || 0))" placeholder="0" class="w-16 h-9 text-sm" />
|
||||||
<span class="text-sm text-muted-foreground whitespace-nowrap">秒</span>
|
<span class="text-sm text-muted-foreground whitespace-nowrap">秒</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -111,13 +111,13 @@ function clearAgentFilter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openCreate() {
|
function openCreate() {
|
||||||
editingTask.value = { name: '', command: '', type: TASK_TYPE.NORMAL, schedule: '0 * * * * *', timeout: 30, work_dir: '', enabled: true, clean_config: '', envs: '' }
|
editingTask.value = { name: '', command: '', type: TASK_TYPE.NORMAL, schedule: '0 * * * * *', timeout: 30, work_dir: '', enabled: true, clean_config: '', envs: '', random_range: 0 }
|
||||||
isEdit.value = false
|
isEdit.value = false
|
||||||
showTaskDialog.value = true
|
showTaskDialog.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function openCreateRepo() {
|
function openCreateRepo() {
|
||||||
editingTask.value = { name: '', type: TASK_TYPE.REPO, schedule: '0 0 0 * * *', timeout: 30, enabled: true, clean_config: '', envs: '' }
|
editingTask.value = { name: '', type: TASK_TYPE.REPO, schedule: '0 0 0 * * *', timeout: 30, enabled: true, clean_config: '', envs: '', random_range: 0 }
|
||||||
isEdit.value = false
|
isEdit.value = false
|
||||||
showRepoDialog.value = true
|
showRepoDialog.value = true
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user