feat: add exec log clean
This commit is contained in:
@@ -23,9 +23,11 @@ func NewTaskController(taskService *services.TaskService, cronService *services.
|
||||
|
||||
func (tc *TaskController) CreateTask(c *gin.Context) {
|
||||
var req struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Command string `json:"command" binding:"required"`
|
||||
Schedule string `json:"schedule" binding:"required"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
Command string `json:"command" binding:"required"`
|
||||
Schedule string `json:"schedule" binding:"required"`
|
||||
Timeout int `json:"timeout"`
|
||||
CleanConfig string `json:"clean_config"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
@@ -38,7 +40,7 @@ func (tc *TaskController) CreateTask(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
task := tc.taskService.CreateTask(req.Name, req.Command, req.Schedule)
|
||||
task := tc.taskService.CreateTask(req.Name, req.Command, req.Schedule, req.Timeout, req.CleanConfig)
|
||||
tc.cronService.AddTask(task)
|
||||
|
||||
utils.Success(c, task)
|
||||
@@ -76,10 +78,12 @@ func (tc *TaskController) UpdateTask(c *gin.Context) {
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Name string `json:"name"`
|
||||
Command string `json:"command"`
|
||||
Schedule string `json:"schedule"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Name string `json:"name"`
|
||||
Command string `json:"command"`
|
||||
Schedule string `json:"schedule"`
|
||||
Timeout int `json:"timeout"`
|
||||
CleanConfig string `json:"clean_config"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
@@ -94,7 +98,7 @@ func (tc *TaskController) UpdateTask(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
task := tc.taskService.UpdateTask(id, req.Name, req.Command, req.Schedule, req.Enabled)
|
||||
task := tc.taskService.UpdateTask(id, req.Name, req.Command, req.Schedule, req.Timeout, req.CleanConfig, req.Enabled)
|
||||
if task == nil {
|
||||
utils.NotFound(c, "任务不存在")
|
||||
return
|
||||
|
||||
+19
-12
@@ -6,19 +6,26 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// CleanConfig 清理配置结构
|
||||
type CleanConfig struct {
|
||||
Type string `json:"type"` // "day" 或 "count"
|
||||
Keep int `json:"keep"` // 保留天数或条数
|
||||
}
|
||||
|
||||
// Task represents a scheduled task
|
||||
type Task struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
Name string `json:"name" gorm:"size:255;not null"`
|
||||
Command string `json:"command" gorm:"type:text;not null"`
|
||||
Schedule string `json:"schedule" gorm:"size:100"` // cron expression
|
||||
Timeout int `json:"timeout" gorm:"default:30"` // 超时时间(分钟),默认30分钟
|
||||
Enabled bool `json:"enabled" gorm:"default:true"`
|
||||
LastRun *LocalTime `json:"last_run"`
|
||||
NextRun *LocalTime `json:"next_run"`
|
||||
CreatedAt LocalTime `json:"created_at"`
|
||||
UpdatedAt LocalTime `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
Name string `json:"name" gorm:"size:255;not null"`
|
||||
Command string `json:"command" gorm:"type:text;not null"`
|
||||
Schedule string `json:"schedule" gorm:"size:100"` // cron expression
|
||||
Timeout int `json:"timeout" gorm:"default:30"` // 超时时间(分钟),默认30分钟
|
||||
CleanConfig string `json:"clean_config" gorm:"size:255;default:''"` // 清理配置 JSON
|
||||
Enabled bool `json:"enabled" gorm:"default:true"`
|
||||
LastRun *LocalTime `json:"last_run"`
|
||||
NextRun *LocalTime `json:"next_run"`
|
||||
CreatedAt LocalTime `json:"created_at"`
|
||||
UpdatedAt LocalTime `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
|
||||
}
|
||||
|
||||
func (Task) TableName() string {
|
||||
@@ -39,4 +46,4 @@ type TaskLog struct {
|
||||
|
||||
func (TaskLog) TableName() string {
|
||||
return constant.TablePrefix + "task_logs"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package services
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -47,6 +48,7 @@ func NewExecutorService(taskService *TaskService) *ExecutorService {
|
||||
// 注册默认回调
|
||||
es.RegisterCallback(es.saveTaskLogCallback)
|
||||
es.RegisterCallback(es.updateStatsCallback)
|
||||
es.RegisterCallback(es.cleanLogsCallback)
|
||||
return es
|
||||
}
|
||||
|
||||
@@ -112,6 +114,53 @@ func (es *ExecutorService) updateStatsCallback(taskID uint, _ string, result *Ex
|
||||
}
|
||||
}
|
||||
|
||||
// CleanConfig 清理配置结构
|
||||
type CleanConfig struct {
|
||||
Type string `json:"type"` // "day" 或 "count"
|
||||
Keep int `json:"keep"` // 保留天数或条数
|
||||
}
|
||||
|
||||
// cleanLogsCallback 清理日志的回调
|
||||
func (es *ExecutorService) cleanLogsCallback(taskID uint, _ string, _ *ExecutionResult) {
|
||||
task := es.taskService.GetTaskByID(int(taskID))
|
||||
if task == nil || task.CleanConfig == "" {
|
||||
return
|
||||
}
|
||||
|
||||
var config CleanConfig
|
||||
if err := json.Unmarshal([]byte(task.CleanConfig), &config); err != nil {
|
||||
logger.Errorf("Failed to parse clean config: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if config.Keep <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var deleted int64
|
||||
switch config.Type {
|
||||
case "day":
|
||||
// 按天清理:删除 N 天前的日志
|
||||
cutoff := time.Now().AddDate(0, 0, -config.Keep)
|
||||
result := database.DB.Where("task_id = ? AND created_at < ?", taskID, cutoff).Delete(&models.TaskLog{})
|
||||
deleted = result.RowsAffected
|
||||
case "count":
|
||||
// 按条数清理:使用子查询删除超出保留数量的旧日志
|
||||
// 先获取第 N 条的 ID 作为边界
|
||||
var boundaryLog models.TaskLog
|
||||
err := database.DB.Where("task_id = ?", taskID).Order("id DESC").Offset(config.Keep - 1).Limit(1).First(&boundaryLog).Error
|
||||
if err == nil {
|
||||
// 删除 ID 小于边界的所有日志
|
||||
result := database.DB.Where("task_id = ? AND id < ?", taskID, boundaryLog.ID).Delete(&models.TaskLog{})
|
||||
deleted = result.RowsAffected
|
||||
}
|
||||
}
|
||||
|
||||
if deleted > 0 {
|
||||
logger.Infof("Cleaned %d logs for task %d", deleted, taskID)
|
||||
}
|
||||
}
|
||||
|
||||
// ExecuteTask executes a task by ID
|
||||
func (es *ExecutorService) ExecuteTask(taskID int) *ExecutionResult {
|
||||
task := es.taskService.GetTaskByID(taskID)
|
||||
|
||||
@@ -11,12 +11,14 @@ func NewTaskService() *TaskService {
|
||||
return &TaskService{}
|
||||
}
|
||||
|
||||
func (ts *TaskService) CreateTask(name, command, schedule string) *models.Task {
|
||||
func (ts *TaskService) CreateTask(name, command, schedule string, timeout int, cleanConfig string) *models.Task {
|
||||
task := &models.Task{
|
||||
Name: name,
|
||||
Command: command,
|
||||
Schedule: schedule,
|
||||
Enabled: true,
|
||||
Name: name,
|
||||
Command: command,
|
||||
Schedule: schedule,
|
||||
Timeout: timeout,
|
||||
CleanConfig: cleanConfig,
|
||||
Enabled: true,
|
||||
}
|
||||
database.DB.Create(task)
|
||||
return task
|
||||
@@ -52,7 +54,7 @@ func (ts *TaskService) GetTaskByID(id int) *models.Task {
|
||||
return &task
|
||||
}
|
||||
|
||||
func (ts *TaskService) UpdateTask(id int, name, command, schedule string, enabled bool) *models.Task {
|
||||
func (ts *TaskService) UpdateTask(id int, name, command, schedule string, timeout int, cleanConfig string, enabled bool) *models.Task {
|
||||
var task models.Task
|
||||
if err := database.DB.First(&task, id).Error; err != nil {
|
||||
return nil
|
||||
@@ -60,6 +62,8 @@ func (ts *TaskService) UpdateTask(id int, name, command, schedule string, enable
|
||||
task.Name = name
|
||||
task.Command = command
|
||||
task.Schedule = schedule
|
||||
task.Timeout = timeout
|
||||
task.CleanConfig = cleanConfig
|
||||
task.Enabled = enabled
|
||||
database.DB.Save(&task)
|
||||
return &task
|
||||
|
||||
Reference in New Issue
Block a user